diff mbox

[SH,committed] Fix cset_zero pattern regressions

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

Commit Message

Oleg Endo Sept. 25, 2016, 7:06 a.m. UTC
Hi,

This fixes a fallout that actually goes back to 5.0 but went unnoticed.
The costs for movt and movrt type of insns were not correctly reported
and ifcvt thus made some bad choices for SH.  A new cset_zero pattern
variant is also required to fix the matching for some recent changes
in the middle end.

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}"

Committed as r240471.
Backports to GCC 6 and GCC 5 will follow.

Cheers,
Oleg


gcc/ChangeLog
        PR target/51244
        * config/sh/sh.c (sh_movt_set_dest, sh_movrt_set_dest): Add overloads.
        (sh_rtx_costs): Handle SET of movt and movrt patterns.
        * cnofig/sh/sh-protos.h (sh_movt_set_dest, sh_movrt_set_dest): Forward
        declare new overloads.
        * config/sh/sh.md (*cset_zero): Add variant that takes a treg_set_expr
        operand.

gcc/testsuite/ChangeLog
        PR target/51244
        * gcc.target/sh/pr51244-11.c: Add more detailed expected insn matching.
diff mbox

Patch

Index: gcc/config/sh/sh-protos.h
===================================================================
--- gcc/config/sh/sh-protos.h	(revision 240470)
+++ gcc/config/sh/sh-protos.h	(working copy)
@@ -235,7 +235,9 @@ 
 
 extern bool sh_is_nott_insn (const rtx_insn* i);
 extern rtx sh_movt_set_dest (const rtx_insn* i);
+extern rtx sh_movt_set_dest (const_rtx i);
 extern rtx sh_movrt_set_dest (const rtx_insn* i);
+extern rtx sh_movrt_set_dest (const_rtx i);
 
 inline bool sh_is_movt_insn (const rtx_insn* i)
 {
Index: gcc/config/sh/sh.c
===================================================================
--- gcc/config/sh/sh.c	(revision 240470)
+++ gcc/config/sh/sh.c	(working copy)
@@ -3208,6 +3208,10 @@ 
 				  / mov_insn_size (mode, TARGET_SH2A));
 	  return true;
         }
+
+      if (sh_movt_set_dest (x) != NULL || sh_movrt_set_dest (x) != NULL)
+	return COSTS_N_INSNS (1);
+
       return false;
 
     /* The cost of a mem access is mainly the cost of the address mode.  */
@@ -11703,13 +11707,15 @@ 
 rtx
 sh_movt_set_dest (const rtx_insn* i)
 {
-  if (i == NULL)
-    return NULL;
+  return i == NULL ? NULL : sh_movt_set_dest (PATTERN (i));
+}
 
-  const_rtx p = PATTERN (i);
-  return GET_CODE (p) == SET
-	 && arith_reg_dest (XEXP (p, 0), SImode)
-	 && t_reg_operand (XEXP (p, 1), VOIDmode) ? XEXP (p, 0) : NULL;
+rtx
+sh_movt_set_dest (const_rtx pat)
+{
+  return GET_CODE (pat) == SET
+	 && arith_reg_dest (XEXP (pat, 0), SImode)
+	 && t_reg_operand (XEXP (pat, 1), VOIDmode) ? XEXP (pat, 0) : NULL;
 }
 
 /* Given an insn, check whether it's a 'movrt' kind of insn, i.e. an insn
@@ -11718,18 +11724,20 @@ 
 rtx
 sh_movrt_set_dest (const rtx_insn* i)
 {
-  if (i == NULL)
-    return NULL;
+  return i == NULL ? NULL : sh_movrt_set_dest (PATTERN (i));
+}
 
-  const_rtx p = PATTERN (i);
-
+rtx
+sh_movrt_set_dest (const_rtx pat)
+{
   /* The negc movrt replacement is inside a parallel.  */
-  if (GET_CODE (p) == PARALLEL)
-    p = XVECEXP (p, 0, 0);
+  if (GET_CODE (pat) == PARALLEL)
+    pat = XVECEXP (pat, 0, 0);
 
-  return GET_CODE (p) == SET
-	 && arith_reg_dest (XEXP (p, 0), SImode)
-	 && negt_reg_operand (XEXP (p, 1), VOIDmode) ? XEXP (p, 0) : NULL;
+  return GET_CODE (pat) == SET
+	 && arith_reg_dest (XEXP (pat, 0), SImode)
+	 && negt_reg_operand (XEXP (pat, 1), VOIDmode) ? XEXP (pat, 0) : NULL;
+
 }
 
 /* Given an insn and a reg number, tell whether the reg dies or is unused
Index: gcc/config/sh/sh.md
===================================================================
--- gcc/config/sh/sh.md	(revision 240470)
+++ gcc/config/sh/sh.md	(working copy)
@@ -8524,6 +8524,24 @@ 
   [(set_attr "type" "arith") ;; poor approximation
    (set_attr "length" "4")])
 
+(define_insn_and_split "*cset_zero"
+  [(set (match_operand:SI 0 "arith_reg_dest")
+	(if_then_else:SI (match_operand 1 "treg_set_expr_not_const01")
+			 (match_dup 0) (const_int 0)))
+   (clobber (reg:SI T_REG))]
+  "TARGET_SH1 && TARGET_ZDCBRANCH && can_create_pseudo_p ()"
+  "#"
+  "&& 1"
+  [(set (match_dup 0)
+	(if_then_else:SI (match_dup 1) (match_dup 0) (const_int 0)))]
+{
+  sh_treg_insns ti = sh_split_treg_set_expr (operands[1], curr_insn);
+  if (ti.remove_trailing_nott ())
+    operands[1] = gen_rtx_EQ (SImode, get_t_reg_rtx (), const0_rtx);
+  else
+    operands[1] = gen_rtx_EQ (SImode, get_t_reg_rtx (), const1_rtx);
+})
+
 (define_expand "cstoresf4"
   [(set (match_operand:SI 0 "register_operand")
 	(match_operator:SI 1 "ordered_comparison_operator"
Index: gcc/testsuite/gcc.target/sh/pr51244-11.c
===================================================================
--- gcc/testsuite/gcc.target/sh/pr51244-11.c	(revision 240470)
+++ gcc/testsuite/gcc.target/sh/pr51244-11.c	(working copy)
@@ -1,8 +1,11 @@ 
 /* Check that zero-displacement branches are used instead of branch-free
-   execution patterns.  */
+   execution patterns.
+   This is usually handled by the *cset_zero patterns.  */
 /* { dg-do compile }  */
-/* { dg-options "-O1 -mzdcbranch" } */
-/* { dg-final { scan-assembler-not "subc|and" } } */
+/* { dg-options "-O1 -mzdcbranch" }  */
+/* { dg-final { scan-assembler-not "subc|and|bra" } }  */
+/* { dg-final { scan-assembler-times "bf\t0f" 1 } }  */
+/* { dg-final { scan-assembler-times "bt\t0f" 1 } }  */
 
 int*
 test_00 (int* s)