diff mbox

[SH,committed] Improve treg_set_expr matching

Message ID 1443448996.2509.133.camel@t-online.de
State New
Headers show

Commit Message

Oleg Endo Sept. 28, 2015, 2:03 p.m. UTC
Hi,

This patch has been hanging around in my queue for a while.  Basically,
it uses reverse_condition to get better matching for treg_set_expr.
Tested on sh-elf with
make -k check RUNTESTFLAGS="--target_board=sh-sim
\{-m2/-ml,-m2/-mb,-m2a/-mb,-m4/-ml,-m4/-mb,-m4a/-ml,-m4a/-mb}"
and no new failures.
Committed as r228202.

Cheers,
Oleg

gcc/ChangeLog:
	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/ChangeLog:
	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.
diff mbox

Patch

Index: gcc/config/sh/predicates.md
===================================================================
--- gcc/config/sh/predicates.md	(revision 228175)
+++ gcc/config/sh/predicates.md	(working copy)
@@ -1158,10 +1158,18 @@ 
 
 ;; 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;
 
@@ -1183,13 +1191,21 @@ 
 
 ;; 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: gcc/config/sh/sh.c
===================================================================
--- gcc/config/sh/sh.c	(revision 228176)
+++ gcc/config/sh/sh.c	(working copy)
@@ -3592,13 +3592,12 @@ 
 
     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 @@ 
     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 @@ 
      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 @@ 
   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);
+      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, EQ);
+      PUT_CODE (op, prev_code);
     }
-  if (result < 0 && GET_CODE (op) == NE)
-    {
-      PUT_CODE (op, EQ);
-      result = recog (PATTERN (i), i, 0);
-      PUT_CODE (op, NE);
-    }
 
+  PUT_MODE (op, prev_op_mode);
   recog_data = prev_recog_data;
   return result >= 0;
 }
@@ -14350,37 +14354,43 @@ 
       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);
+
+      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);
     }
 
-  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
      will be emitted as part of the outer insn and then split again.  */
Index: gcc/testsuite/gcc.target/sh/pr54236-1.c
===================================================================
--- gcc/testsuite/gcc.target/sh/pr54236-1.c	(revision 228175)
+++ gcc/testsuite/gcc.target/sh/pr54236-1.c	(working copy)
@@ -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 @@ 
   /* 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);
+}
+
Index: gcc/testsuite/gcc.target/sh/pr54236-5.c
===================================================================
--- gcc/testsuite/gcc.target/sh/pr54236-5.c	(revision 0)
+++ gcc/testsuite/gcc.target/sh/pr54236-5.c	(working copy)
@@ -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;
+}
Index: gcc/testsuite/gcc.target/sh/pr54236-6.c
===================================================================
--- gcc/testsuite/gcc.target/sh/pr54236-6.c	(revision 0)
+++ gcc/testsuite/gcc.target/sh/pr54236-6.c	(working copy)
@@ -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: gcc/testsuite/gcc.target/sh/pr59533-1.c
===================================================================
--- gcc/testsuite/gcc.target/sh/pr59533-1.c	(revision 228175)
+++ gcc/testsuite/gcc.target/sh/pr59533-1.c	(working copy)
@@ -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 @@ 
   /* 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;
+}