This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[SH][committed] FIx PR 63986


Hi,

The attached patch fixes PR 63986.
Tested with
make -k check RUNTESTFLAGS="--target_board=sh-sim\{-m4/-ml,-m4/-mb}"
and no new failures.  Committed as r217968.

Cheers,
Oleg

gcc/ChangeLog:
	PR target/63986
	PR target/51244
	* config/sh/sh.c (sh_is_logical_t_store_expr,
	sh_try_omit_signzero_extend): Use rtx_insn* for insn argument.
	(sh_split_movrt_negc_to_movt_xor): New function.
	(sh_find_set_of_reg): Move to ...
	* config/sh/sh-protos.h (sh_find_set_of_reg): ... here and convert
	to template function.
	(set_of_reg): Use rtx_insn* for insn member.
	(sh_is_logical_t_store_expr, sh_try_omit_signzero_extend): Use
	rtx_insn* for insn argument.
	* config/sh/sh.md (movrt_negc, *movrt_negc): Split into movt-xor
	sequence using new sh_split_movrt_negc_to_movt_xor function.
	(movrt_xor): Allow also for SH2A.
	(*movt_movrt): Delete insns and splits.

Index: gcc/config/sh/sh.md
===================================================================
--- gcc/config/sh/sh.md	(revision 217957)
+++ gcc/config/sh/sh.md	(working copy)
@@ -11445,13 +11445,21 @@
   DONE;
 })
 
-(define_insn "movrt_negc"
+(define_insn_and_split "movrt_negc"
   [(set (match_operand:SI 0 "arith_reg_dest" "=r")
-	(xor:SI (match_operand:SI 1 "t_reg_operand" "") (const_int 1)))
+	(xor:SI (match_operand:SI 1 "t_reg_operand") (const_int 1)))
    (set (reg:SI T_REG) (const_int 1))
    (use (match_operand:SI 2 "arith_reg_operand" "r"))]
   "TARGET_SH1"
   "negc	%2,%0"
+  "&& 1"
+  [(const_int 0)]
+{
+  if (sh_split_movrt_negc_to_movt_xor (curr_insn, operands))
+    DONE;
+  else
+    FAIL;
+}
   [(set_attr "type" "arith")])
 
 ;; The -1 constant will not be CSE-ed for the *movrt_negc pattern, but the
@@ -11460,17 +11468,25 @@
 ;; generating a pseudo reg before reload.
 (define_insn_and_split "*movrt_negc"
   [(set (match_operand:SI 0 "arith_reg_dest" "=r")
-	(xor:SI (match_operand:SI 1 "t_reg_operand" "") (const_int 1)))
+	(xor:SI (match_operand:SI 1 "t_reg_operand") (const_int 1)))
    (clobber (match_scratch:SI 2 "=r"))
    (clobber (reg:SI T_REG))]
   "TARGET_SH1 && ! TARGET_SH2A"
   "#"
-  "&& reload_completed"
-  [(set (match_dup 2) (const_int -1))
-   (parallel
-       [(set (match_dup 0) (xor:SI (match_dup 1) (const_int 1)))
-	(set (reg:SI T_REG) (const_int 1))
-	(use (match_dup 2))])])
+  "&& 1"
+  [(const_int 0)]
+{
+  if (sh_split_movrt_negc_to_movt_xor (curr_insn, operands))
+    DONE;
+  else if (reload_completed)
+    {
+      emit_move_insn (operands[2], gen_int_mode (-1, SImode));
+      emit_insn (gen_movrt_negc (operands[0], operands[1], operands[2]));
+      DONE;
+    }
+  else
+    FAIL;
+})
 
 ;; Store the negated T bit in a reg using r0 and xor.  This one doesn't
 ;; clobber the T bit, which is useful when storing the T bit and the
@@ -11481,45 +11497,12 @@
   [(set (match_operand:SI 0 "arith_reg_dest" "=z")
 	(xor:SI (match_operand:SI 1 "t_reg_operand") (const_int 1)))
    (use (reg:SI T_REG))]
-  "TARGET_SH1 && !TARGET_SH2A"
+  "TARGET_SH1"
   "#"
   "&& reload_completed"
   [(set (match_dup 0) (reg:SI T_REG))
    (set (match_dup 0) (xor:SI (match_dup 0) (const_int 1)))])
 
-;; Store the T bit and the negated T bit in two regs in parallel.  There is
-;; no real insn to do that, but specifying this pattern will give combine
-;; some opportunities.
-(define_insn_and_split "*movt_movrt"
-  [(parallel [(set (match_operand:SI 0 "arith_reg_dest")
-		   (match_operand:SI 1 "negt_reg_operand"))
-	      (set (match_operand:SI 2 "arith_reg_dest")
-		   (match_operand:SI 3 "t_reg_operand"))])]
-  "TARGET_SH1"
-  "#"
-  "&& 1"
-  [(const_int 0)]
-{
-  rtx i = TARGET_SH2A
-	  ? gen_movrt (operands[0], get_t_reg_rtx ())
-	  : gen_movrt_xor (operands[0], get_t_reg_rtx ());
-  
-  emit_insn (i);
-  emit_insn (gen_movt (operands[2], get_t_reg_rtx ()));
-  DONE;
-})
-
-(define_insn_and_split "*movt_movrt"
-  [(parallel [(set (match_operand:SI 0 "arith_reg_dest")
-		   (match_operand:SI 1 "t_reg_operand"))
-	      (set (match_operand:SI 2 "arith_reg_dest")
-		   (match_operand:SI 3 "negt_reg_operand"))])]
-  "TARGET_SH1"
-  "#"
-  "&& 1"
-  [(parallel [(set (match_dup 2) (match_dup 3))
-	      (set (match_dup 0) (match_dup 1))])])
-
 ;; Use negc to store the T bit in a MSB of a reg in the following way:
 ;;	T = 1: 0x80000000 -> reg
 ;;	T = 0: 0x7FFFFFFF -> reg
Index: gcc/config/sh/sh-protos.h
===================================================================
--- gcc/config/sh/sh-protos.h	(revision 217957)
+++ gcc/config/sh/sh-protos.h	(working copy)
@@ -165,7 +165,7 @@
 {
   /* The insn where sh_find_set_of_reg stopped looking.
      Can be NULL_RTX if the end of the insn list was reached.  */
-  rtx insn;
+  rtx_insn* insn;
 
   /* The set rtx of the specified reg if found, NULL_RTX otherwise.  */
   const_rtx set_rtx;
@@ -175,9 +175,47 @@
   rtx set_src;
 };
 
-extern set_of_reg sh_find_set_of_reg (rtx reg, rtx insn, rtx_insn *(*stepfunc)(rtx));
-extern bool sh_is_logical_t_store_expr (rtx op, rtx insn);
-extern rtx sh_try_omit_signzero_extend (rtx extended_op, rtx insn);
+/* Given a reg rtx and a start insn, try to find the insn that sets the
+   specified reg by using the specified insn stepping function, such as 
+   'prev_nonnote_insn_bb'.  When the insn is found, try to extract the rtx
+   of the reg set.  */
+template <typename F> inline set_of_reg
+sh_find_set_of_reg (rtx reg, rtx_insn* insn, F stepfunc)
+{
+  set_of_reg result;
+  result.insn = insn;
+  result.set_rtx = NULL_RTX;
+  result.set_src = NULL_RTX;
+
+  if (!REG_P (reg) || insn == NULL_RTX)
+    return result;
+
+  for (result.insn = stepfunc (insn); result.insn != NULL_RTX;
+       result.insn = stepfunc (result.insn))
+    {
+      if (BARRIER_P (result.insn))
+	return result;
+      if (!NONJUMP_INSN_P (result.insn))
+	continue;
+      if (reg_set_p (reg, result.insn))
+	{
+	  result.set_rtx = set_of (reg, result.insn);
+
+	  if (result.set_rtx == NULL_RTX || GET_CODE (result.set_rtx) != SET)
+	    return result;
+
+	  result.set_src = XEXP (result.set_rtx, 1);
+	  return result;
+	}
+    }
+
+  return result;
+}
+
+extern bool sh_is_logical_t_store_expr (rtx op, rtx_insn* insn);
+extern rtx sh_try_omit_signzero_extend (rtx extended_op, rtx_insn* insn);
+extern bool sh_split_movrt_negc_to_movt_xor (rtx_insn* curr_insn,
+					     rtx operands[]);
 #endif /* RTX_CODE */
 
 extern void sh_cpu_cpp_builtins (cpp_reader* pfile);
Index: gcc/config/sh/sh.c
===================================================================
--- gcc/config/sh/sh.c	(revision 217957)
+++ gcc/config/sh/sh.c	(working copy)
@@ -13503,47 +13503,10 @@
   Manual insn combine support code.
 */
 
-/* Given a reg rtx and a start insn, try to find the insn that sets the
-   specified reg by using the specified insn stepping function, such as 
-   'prev_nonnote_insn_bb'.  When the insn is found, try to extract the rtx
-   of the reg set.  */
-set_of_reg
-sh_find_set_of_reg (rtx reg, rtx insn, rtx_insn *(*stepfunc)(rtx))
-{
-  set_of_reg result;
-  result.insn = insn;
-  result.set_rtx = NULL_RTX;
-  result.set_src = NULL_RTX;
-
-  if (!REG_P (reg) || insn == NULL_RTX)
-    return result;
-
-  for (result.insn = stepfunc (insn); result.insn != NULL_RTX;
-       result.insn = stepfunc (result.insn))
-    {
-      if (BARRIER_P (result.insn))
-	return result;
-      if (!NONJUMP_INSN_P (result.insn))
-	continue;
-      if (reg_set_p (reg, result.insn))
-	{
-	  result.set_rtx = set_of (reg, result.insn);
-
-	  if (result.set_rtx == NULL_RTX || GET_CODE (result.set_rtx) != SET)
-	    return result;
-
-	  result.set_src = XEXP (result.set_rtx, 1);
-	  return result;
-	}
-    }
-
-  return result;
-}
-
 /* Given an op rtx and an insn, try to find out whether the result of the
    specified op consists only of logical operations on T bit stores.  */
 bool
-sh_is_logical_t_store_expr (rtx op, rtx insn)
+sh_is_logical_t_store_expr (rtx op, rtx_insn* insn)
 {
   if (!logical_operator (op, SImode))
     return false;
@@ -13579,7 +13542,7 @@
    by a simple reg-reg copy.  If so, the replacement reg rtx is returned,
    NULL_RTX otherwise.  */
 rtx
-sh_try_omit_signzero_extend (rtx extended_op, rtx insn)
+sh_try_omit_signzero_extend (rtx extended_op, rtx_insn* insn)
 {
   if (REG_P (extended_op))
     extended_op = extended_op;
@@ -13609,6 +13572,42 @@
   return NULL_RTX;
 }
 
+/* Given the current insn, which is assumed to be a movrt_negc insn, try to
+   figure out whether it should be converted into a movt-xor sequence in
+   the movrt_negc splitter.
+   Returns true if insns have been modified and the splitter has succeeded.  */
+bool
+sh_split_movrt_negc_to_movt_xor (rtx_insn* curr_insn, rtx operands[])
+{
+  /* In cases such as
+	tst	r4,r4
+	mov	#-1,r1
+	negc	r1,r1
+	tst	r4,r4
+     we can replace the T bit clobbering negc with a movt-xor sequence and
+     eliminate the redundant comparison.
+     Because the xor insn depends on register allocation results, allow this
+     only before reload.  */
+  if (!can_create_pseudo_p ())
+    return false;
+
+  set_of_reg t_before_negc = sh_find_set_of_reg (get_t_reg_rtx (), curr_insn,
+						 prev_nonnote_insn_bb);
+  set_of_reg t_after_negc = sh_find_set_of_reg (get_t_reg_rtx (), curr_insn,
+						next_nonnote_insn_bb);
+
+  if (t_before_negc.set_rtx != NULL_RTX && t_after_negc.set_rtx != NULL_RTX
+      && rtx_equal_p (t_before_negc.set_rtx, t_after_negc.set_rtx)
+      && !reg_used_between_p (get_t_reg_rtx (), curr_insn, t_after_negc.insn))
+    {
+      emit_insn (gen_movrt_xor (operands[0], get_t_reg_rtx ()));
+      set_insn_deleted (t_after_negc.insn);
+      return true;
+    }
+  else
+    return false;
+}
+
 static void
 sh_emit_mode_set (int entity ATTRIBUTE_UNUSED, int mode,
 		  int prev_mode, HARD_REG_SET regs_live ATTRIBUTE_UNUSED)

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]