re PR target/54236 ([SH] Improve addc and subc insn utilization)
authorOleg Endo <olegendo@gcc.gnu.org>
Mon, 28 Sep 2015 14:00:44 +0000 (14:00 +0000)
committerOleg Endo <olegendo@gcc.gnu.org>
Mon, 28 Sep 2015 14:00:44 +0000 (14:00 +0000)
gcc/
PR target/54236
* config/sh/predicates.md (t_reg_operand, negt_reg_operand): Allow
and handle ne and eq codes.
* config/sh/sh.c (sh_rtx_costs): Adjust matching of tst #imm,r0 insn.
(sh_recog_treg_set_expr): Early accept negt_reg_operand.  Eearly reject
CONST_INT_P.  Use reverse_condition.
(sh_split_treg_set_expr): Likewise.

gcc/testsuite/
PR target/54236
* gcc.target/sh/pr54236-1.c (test_09, test_10, test_11): New.
* gcc.target/sh/pr59533-1.c (test_23, test_24, test_25, test_26,
test_27): New.
* gcc.target/sh/pr54236-5.c: New.
* gcc.target/sh/pr54236-6.c: New.

From-SVN: r228202

gcc/ChangeLog
gcc/config/sh/predicates.md
gcc/config/sh/sh.c
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.target/sh/pr54236-1.c
gcc/testsuite/gcc.target/sh/pr54236-5.c [new file with mode: 0644]
gcc/testsuite/gcc.target/sh/pr54236-6.c [new file with mode: 0644]
gcc/testsuite/gcc.target/sh/pr59533-1.c

index e066bd76b82319b1b7921afea9b7d83c8b39dbfd..6b9af395919c2a00981399023bace8ad80c52326 100644 (file)
@@ -1,3 +1,13 @@
+2015-09-28  Oleg Endo  <olegendo@gcc.gnu.org>
+
+       PR target/54236
+       * config/sh/predicates.md (t_reg_operand, negt_reg_operand): Allow
+       and handle ne and eq codes.
+       * config/sh/sh.c (sh_rtx_costs): Adjust matching of tst #imm,r0 insn.
+       (sh_recog_treg_set_expr): Early accept negt_reg_operand.  Eearly reject
+       CONST_INT_P.  Use reverse_condition.
+       (sh_split_treg_set_expr): Likewise.
+
 2015-09-28  James Greenhalgh  <james.greenhalgh@arm.com>
 
        * config/arm/types.md (type): Add rotate_imm.
index 6f0d89e1f196463470809d2ba4b24322b0cb80b8..b847ae74a9d27e16d617bb6dbc09fcf18e1276b3 100644 (file)
 
 ;; A predicate describing the T bit register in any form.
 (define_predicate "t_reg_operand"
-  (match_code "reg,subreg,sign_extend,zero_extend")
+  (match_code "reg,subreg,sign_extend,zero_extend,ne,eq")
 {
   switch (GET_CODE (op))
     {
+      case EQ:
+       return t_reg_operand (XEXP (op, 0), GET_MODE (XEXP (op, 0)))
+              && XEXP (op, 1) == const1_rtx;
+
+      case NE:
+       return t_reg_operand (XEXP (op, 0), GET_MODE (XEXP (op, 0)))
+              && XEXP (op, 1) == const0_rtx;
+
       case REG:
        return REGNO (op) == T_REG;
 
 
 ;; A predicate describing a negated T bit register.
 (define_predicate "negt_reg_operand"
-  (match_code "subreg,xor")
+  (match_code "subreg,xor,ne,eq")
 {
   switch (GET_CODE (op))
     {
+      case EQ:
+       return t_reg_operand (XEXP (op, 0), GET_MODE (XEXP (op, 0)))
+              && XEXP (op, 1) == const0_rtx;
+
+      case NE:
+       return t_reg_operand (XEXP (op, 0), GET_MODE (XEXP (op, 0)))
+              && XEXP (op, 1) == const1_rtx;
+
       case XOR:
        return t_reg_operand (XEXP (op, 0), GET_MODE (XEXP (op, 0)))
-              && satisfies_constraint_M (XEXP (op, 1));
+              && XEXP (op, 1) == const1_rtx;
 
       case SUBREG:
        return negt_reg_operand (XEXP (op, 0), GET_MODE (XEXP (op, 0)));
index 1a859724ff174301a6942eab0086a0f44e0211f1..b203258102af2b84bf2837bc0912bc47d3df3427 100644 (file)
@@ -3592,13 +3592,12 @@ sh_rtx_costs (rtx x, machine_mode mode ATTRIBUTE_UNUSED, int outer_code,
 
     case EQ:
       /* An and with a constant compared against zero is
-        most likely going to be a TST #imm, R0 instruction.
-        Notice that this does not catch the zero_extract variants from
-        the md file.  */
+        most likely going to be a TST #imm, R0 instruction.  */
       if (XEXP (x, 1) == const0_rtx
-          && (GET_CODE (XEXP (x, 0)) == AND
-              || (SUBREG_P (XEXP (x, 0))
-                 && GET_CODE (SUBREG_REG (XEXP (x, 0))) == AND)))
+          && ((GET_CODE (XEXP (x, 0)) == AND
+               || (SUBREG_P (XEXP (x, 0))
+                  && GET_CODE (SUBREG_REG (XEXP (x, 0))) == AND))
+             || GET_CODE (XEXP (x, 0)) == ZERO_EXTRACT))
        {
          *total = 1;
          return true;
@@ -14200,7 +14199,8 @@ sh_recog_treg_set_expr (rtx op, machine_mode mode)
     return false;
 
   /* Early accept known possible operands before doing recog.  */
-  if (op == const0_rtx || op == const1_rtx || t_reg_operand (op, mode))
+  if (op == const0_rtx || op == const1_rtx || t_reg_operand (op, mode)
+      || negt_reg_operand (op, mode))
     return true;
 
   /* Early reject impossible operands before doing recog.
@@ -14209,8 +14209,8 @@ sh_recog_treg_set_expr (rtx op, machine_mode mode)
      such as lower-subreg will bail out.  Some insns such as SH4A movua are
      done with UNSPEC, so must reject those, too, or else it would result
      in an invalid reg -> treg move.  */
-  if (register_operand (op, mode) || memory_operand (op, mode)
-      || sh_unspec_insn_p (op))
+  if (CONST_INT_P (op) || register_operand (op, mode)
+      || memory_operand (op, mode) || sh_unspec_insn_p (op))
     return false;
 
   if (!can_create_pseudo_p ())
@@ -14230,26 +14230,30 @@ sh_recog_treg_set_expr (rtx op, machine_mode mode)
   SET_PREV_INSN (i) = NULL;
   SET_NEXT_INSN (i) = NULL;
 
+  /* If the comparison op doesn't have a result mode, set it to SImode.  */
+  machine_mode prev_op_mode = GET_MODE (op);
+  if (COMPARISON_P (op) && prev_op_mode == VOIDmode)
+    PUT_MODE (op, SImode);
+
   int result = recog (PATTERN (i), i, 0);
 
-  /* It seems there is no insn like that.  Create a simple negated
-     version and try again.  If we hit a negated form, we'll allow that
-     and append a nott sequence when splitting out the insns.  Insns that
-     do the split can then remove the trailing nott if they know how to
-     deal with it.  */
-  if (result < 0 && GET_CODE (op) == EQ)
+  /* It seems there is no insn like that.  Create a negated version and
+     try again.  If we hit a negated form, we'll allow that and append a
+     nott sequence when splitting out the insns.  Insns that do the split
+     can then remove the trailing nott if they know how to deal with it.  */
+  if (result < 0 && COMPARISON_P (op))
     {
-      PUT_CODE (op, NE);
-      result = recog (PATTERN (i), i, 0);
-      PUT_CODE (op, EQ);
-    }
-  if (result < 0 && GET_CODE (op) == NE)
-    {
-      PUT_CODE (op, EQ);
+      machine_mode cmp_mode = GET_MODE (XEXP (op, 0));
+      if (cmp_mode == VOIDmode)
+        cmp_mode = GET_MODE (XEXP (op, 1));
+
+      rtx_code prev_code = GET_CODE (op);
+      PUT_CODE (op, reverse_condition (GET_CODE (op)));
       result = recog (PATTERN (i), i, 0);
-      PUT_CODE (op, NE);
+      PUT_CODE (op, prev_code);
     }
 
+  PUT_MODE (op, prev_op_mode);
   recog_data = prev_recog_data;
   return result >= 0;
 }
@@ -14350,36 +14354,42 @@ sh_split_treg_set_expr (rtx x, rtx_insn* curr_insn)
       fprintf (dump_file, "\n");
     }
 
+  /* If the insn is not found, we will try a negated form and append
+     a nott.  */
+  bool append_nott = false;
+
   /* We are going to invoke recog/split_insns in a re-entrant way and thus
      have to capture its current state and restore it afterwards.  */
   recog_data_d prev_recog_data = recog_data;
 
-  int insn_code = recog (PATTERN (i), i, 0);
-
-  /* If the insn was not found, see if we matched the negated form before
-     and append a nott.  */
-  bool append_nott = false;
-
-  if (insn_code < 0 && GET_CODE (x) == EQ)
+  if (negt_reg_operand (x, GET_MODE (x)))
     {
-      PUT_CODE (x, NE);
-      insn_code = recog (PATTERN (i), i, 0);
-      if (insn_code >= 0)
-       append_nott = true;
-      else
-       PUT_CODE (x, EQ);
+      /* This is a normal movt followed by a nott.  It will be converted
+        into a movrt after initial expansion.  */
+      XEXP (PATTERN (i), 1) = get_t_reg_rtx ();
+      append_nott = true;
     }
-  if (insn_code < 0 && GET_CODE (x) == NE)
+  else
     {
-      PUT_CODE (x, EQ);
-      insn_code = recog (PATTERN (i), i, 0);
-      if (insn_code >= 0)
-       append_nott = true;
-      else
-       PUT_CODE (x, NE);
-    }
+      /* If the comparison op doesn't have a mode set, set it to SImode.  */
+      if (COMPARISON_P (x) && GET_MODE (x) == VOIDmode)
+       PUT_MODE (x, SImode);
+
+      int insn_code = recog (PATTERN (i), i, 0);
 
-  gcc_assert (insn_code >= 0);
+      if (insn_code < 0 && COMPARISON_P (x))
+       {
+         machine_mode cmp_mode = GET_MODE (XEXP (x, 0));
+         if (cmp_mode == VOIDmode)
+           cmp_mode = GET_MODE (XEXP (x, 1));
+
+         PUT_CODE (x, reverse_condition (GET_CODE (x)));
+         insn_code = recog (PATTERN (i), i, 0);
+         append_nott = true;
+       }
+
+      gcc_assert (insn_code >= 0);
+    }
 
   /* Try to recursively split the insn.  Some insns might refuse to split
      any further while we are in the treg_set_expr splitting phase.  They
index d5dd6f21e08b7db0a63cd44214e61aca15ff20ae..c2f693b7e3391730b46ad64c429c8dc50877d989 100644 (file)
@@ -1,3 +1,12 @@
+2015-09-28  Oleg Endo  <olegendo@gcc.gnu.org>
+
+       PR target/54236
+       * gcc.target/sh/pr54236-1.c (test_09, test_10, test_11): New.
+       * gcc.target/sh/pr59533-1.c (test_23, test_24, test_25, test_26,
+       test_27): New.
+       * gcc.target/sh/pr54236-5.c: New.
+       * gcc.target/sh/pr54236-6.c: New.
+
 2015-09-28  Kyrylo Tkachov  <kyrylo.tkachov@arm.com>
 
        PR rtl-optimization/67456
index b5c35464a6a6589af7a44ce5578357fa6a0175ef..7d89a5ee1701e5b8d88e19c3c5cd16609c59dfe9 100644 (file)
@@ -4,8 +4,8 @@
 /* { dg-do compile }  */
 /* { dg-options "-O1" } */
 /* { dg-skip-if "" { "sh*-*-*" } { "-m5*"} { "" } } */
-/* { dg-final { scan-assembler-times "addc" 4 } } */
-/* { dg-final { scan-assembler-times "subc" 3 } } */
+/* { dg-final { scan-assembler-times "addc" 6 } } */
+/* { dg-final { scan-assembler-times "subc" 4 } } */
 /* { dg-final { scan-assembler-times "sett" 5 } } */
 
 /* { dg-final { scan-assembler-times "negc" 2 { target { ! sh2a } } } }  */
@@ -86,3 +86,25 @@ test_08 (int a)
   /* 1x addc, 1x sett  */
   return (a << 1) + 1;
 }
+
+unsigned int
+test_09 (unsigned int x)
+{
+  /* 1x tst, 1x addc  */
+  return x - (x != 0);
+}
+
+unsigned int
+test_10 (unsigned int x)
+{
+  /* 1x tst, 1x subc  */
+  return x + (x == 0);
+}
+
+unsigned int
+test_11 (unsigned int x)
+{
+  /* 1x tst, 1x addc  */
+  return x + (x != 0);
+}
+
diff --git a/gcc/testsuite/gcc.target/sh/pr54236-5.c b/gcc/testsuite/gcc.target/sh/pr54236-5.c
new file mode 100644 (file)
index 0000000..082b4f0
--- /dev/null
@@ -0,0 +1,89 @@
+/* Check that addc and subc instructions are generated as expected in
+   combination with ifcvt.  */
+/* { dg-do compile }  */
+/* { dg-options "-O2" }  */
+
+/* { dg-final { scan-assembler-times "subc" 4 { target { ! sh2a } } } }  */
+/* { dg-final { scan-assembler-times "addc" 4 { target { ! sh2a } } } }  */
+/* { dg-final { scan-assembler-times "not\t" 0 { target { ! sh2a } } } }  */
+
+/* { dg-final { scan-assembler-times "subc" 4 { target { sh2a } } } }  */
+/* { dg-final { scan-assembler-times "addc" 4 { target { sh2a } } } }  */
+/* { dg-final { scan-assembler-times "nott" 0 { target { sh2a } } } }  */
+
+/* { dg-final { scan-assembler-times "tst\t" 4 } }  */
+/* { dg-final { scan-assembler-times "cmp/eq" 1 } }  */
+/* { dg-final { scan-assembler-times "cmp/pl" 2 } }  */
+/* { dg-final { scan-assembler-times "cmp/gt" 1 } }  */
+
+/* { dg-final { scan-assembler-not "movt" } }  */
+/* { dg-final { scan-assembler-not "negc" } }  */
+/* { dg-final { scan-assembler-not "movrt" } }  */
+
+int
+test_00 (int x, int y)
+{
+  /* 1x tst, 1x subc  */
+  if (y)
+    ++x;
+  return x;
+}
+
+int
+test_01 (int x, int y)
+{
+  /* 1x tst, 1x addc  */
+  if (y)
+    --x;
+  return x;
+}
+
+int
+test_02 (int x, int y)
+{
+  /* 1x tst, 1x addc  */
+  if (!y)
+    ++x;
+  return x;
+}
+
+int
+test_03 (int x, int y)
+{
+  /* 1x tst, 1x subc  */
+  if (!y)
+    --x;
+  return x;
+}
+
+int
+test_04 (int x, int y)
+{
+  /* 1x cmp/eq, 1x addc  */
+  if (y == x)
+    ++x;
+  return x;
+}
+
+int
+test_05 (int x, int y)
+{
+  /* 1x cmp/gt, 1x subc  */
+  if (y < 4)
+    ++x;
+  return x;
+}
+
+int
+test_06 (int x)
+{
+  /* 1x cmp/pl, 1x addc  */
+  return x > 0 ? x + 1 : x;
+}
+
+int
+test_07 (int x)
+{
+  /* 1x cmp/pl, 1x subc  */
+  return x > 0 ? x - 1 : x;
+}
diff --git a/gcc/testsuite/gcc.target/sh/pr54236-6.c b/gcc/testsuite/gcc.target/sh/pr54236-6.c
new file mode 100644 (file)
index 0000000..9920618
--- /dev/null
@@ -0,0 +1,75 @@
+/* In this snippet, there was a missed subc case:
+       tst     #1,r0
+       movt    r0
+       neg     r0,r0
+
+   which should be:
+       tst     #1,r0
+       subc    r0,r0
+*/
+
+/* { dg-do compile }  */
+/* { dg-options "-O2" }  */
+
+/* { dg-final { scan-assembler-times {tst      #1,r0} 1 } }  */
+/* { dg-final { scan-assembler-times {subc     r} 1 } }  */
+
+/* { dg-final { scan-assembler-not "movt|not|neg\movrt" } }  */
+
+
+struct inode
+{
+  unsigned int i_gid;
+};
+
+struct iattr
+{
+  unsigned int ia_valid;
+  unsigned int ia_gid;
+};
+
+struct task_struct
+{
+  unsigned long flags;
+  unsigned int cap_effective;
+};
+
+extern int in_group_p (unsigned int);
+
+static inline struct task_struct*
+get_current (void)
+{
+  struct task_struct *current;
+  return current;
+}
+
+static inline int
+capable (int cap)
+{
+  if (((get_current()->cap_effective) & (1 << (cap))))
+    {
+      get_current()->flags |= 0x00000100;
+      return 1;
+    }
+  return 0;
+}
+
+int
+inode_change_ok (struct inode *inode, struct iattr *attr)
+{
+  int retval = -1;
+  unsigned int ia_valid = attr->ia_valid;
+
+  if (ia_valid & 512)
+    goto fine;
+
+  if ((ia_valid & 4)
+      && (!in_group_p(attr->ia_gid) && attr->ia_gid != inode->i_gid)
+      && !capable(0))
+    goto error;
+
+fine:
+ retval = 0;
+error:
+ return retval;
+}
index f45e4b83d715e219afb1c0c724bd8da877fa9e30..c5c6c7e141b7d79f6b0bff2bae6d80ec8c4ee2f4 100644 (file)
@@ -9,13 +9,13 @@
 /* { dg-final { scan-assembler-times "and" 3 } }  */
 /* { dg-final { scan-assembler-times "extu.b" 5 } }  */
 
-/* { dg-final { scan-assembler-times "cmp/pz" 22 { target { ! sh2a } } } }  */
-/* { dg-final { scan-assembler-times "addc" 3 { target { ! sh2a } } } }  */
-/* { dg-final { scan-assembler-times "subc" 12 { target { ! sh2a } } } }  */
+/* { dg-final { scan-assembler-times "cmp/pz" 27 { target { ! sh2a } } } }  */
+/* { dg-final { scan-assembler-times "addc" 4 { target { ! sh2a } } } }  */
+/* { dg-final { scan-assembler-times "subc" 16 { target { ! sh2a } } } }  */
 
-/* { dg-final { scan-assembler-times "cmp/pz" 20 { target { sh2a } } } }  */
-/* { dg-final { scan-assembler-times "addc" 5 { target { sh2a } } } }  */
-/* { dg-final { scan-assembler-times "subc" 10 { target { sh2a } } } }  */
+/* { dg-final { scan-assembler-times "cmp/pz" 25 { target { sh2a } } } }  */
+/* { dg-final { scan-assembler-times "addc" 6 { target { sh2a } } } }  */
+/* { dg-final { scan-assembler-times "subc" 14 { target { sh2a } } } }  */
 /* { dg-final { scan-assembler-times "bld" 2 { target { sh2a } } } }  */
 
 int
@@ -183,3 +183,38 @@ test_22 (int x)
   /* 1x cmp/pz, 1x movt  */
   return (x >> 31) + 1;
 }
+
+int
+test_23 (int x)
+{
+  /* 1x cmp/pz, 1x subc */
+  return x < 0 ? x + 1 : x;
+}
+
+unsigned int
+test_24 (unsigned int x)
+{
+  /* 1x cmp/pz, 1x subc */
+  return x & 0x80000000 ? x + 1 : x;
+}
+
+unsigned int
+test_25 (unsigned int x)
+{
+  /* 1x cmp/pz, 1x subc */
+  return x >> 31 ? x + 1 : x;
+}
+
+int
+test_26 (int x)
+{
+  /* 1x cmp/pz, 1x subc  */
+  return x >> 31 ? x + 1 : x;
+}
+
+int
+test_27 (int x, int y, int z)
+{
+  /* 1x cmp/pz, 1x addc  */
+  return 1 - ((x >> 4) < 0) + z;
+}