Hi,

The attached patch fixes PR 63783.
Tested on trunk with
make -k check RUNTESTFLAGS="--target_board=sh-sim\{-m4/-ml,-m4/-mb}"
and no new failures.
Tested on 4.9 branch with make all-gcc and verifying that the
problematic test case is OK.

Committed on trunk as r217969 and on 4.9 branch as r217970.

Cheers,
Oleg

gcc/ChangeLog:
        PR target/63783
        PR target/51244
        * config/sh/sh_treg_combine.cc (sh_treg_combine::make_not_reg_insn):
        Do not emit bitwise not insn.  Emit logical not insn sequence instead.
        Adjust related comments throughout the file.

gcc/testsuite/ChangeLog:
        PR target/63783
        PR target/51244
        * gcc.target/sh/torture/pr63783-1.c: New.
        * gcc.target/sh/torture/pr63783-2.c: New.
        * gcc.target/sh/pr51244-20.c: Adjust.
        * gcc.target/sh/pr51244-20-sh2a.c: Adjust.
Index: gcc/config/sh/sh_treg_combine.cc
===================================================================
--- gcc/config/sh/sh_treg_combine.cc	(revision 217823)
+++ gcc/config/sh/sh_treg_combine.cc	(working copy)
@@ -95,14 +95,17 @@
 
 In [bb 4] elimination of the comparison would require inversion of the branch
 condition and compensation of other BBs.
-Instead an inverting reg-move can be used:
+Instead the comparison in [bb 3] can be replaced with the comparison in [bb 5]
+by using a reg-reg move.  In [bb 4] a logical not is used to compensate the
+inverted condition.
 
 [bb 3]
 (set (reg:SI 167) (reg:SI 173))
 -> bb 5
 
 [BB 4]
-(set (reg:SI 167) (not:SI (reg:SI 177)))
+(set (reg:SI 147 t) (eq:SI (reg:SI 177) (const_int 0)))
+(set (reg:SI 167) (reg:SI 147 t))
 -> bb 5
 
 [bb 5]
@@ -231,9 +234,9 @@
       and replace the comparisons in the BBs with reg-reg copies to get the
       operands in place (create new pseudo regs).
 
-    - If the cstores differ, try to apply the special case
-        (eq (reg) (const_int 0)) -> inverted = (not (reg)).
-      for the subordinate cstore types and eliminate the dominating ones.
+    - If the cstores differ and the comparison is a test against zero,
+      use reg-reg copies for the dominating cstores and logical not cstores
+      for the subordinate cstores.
 
 - If the comparison types in the BBs are not the same, or the first approach
   doesn't work out for some reason, try to eliminate the comparison before the
@@ -576,7 +579,8 @@
   bool can_extend_ccreg_usage (const bb_entry& e,
 			       const cbranch_trace& trace) const;
 
-  // Create an insn rtx that is a negating reg move (not operation).
+  // Create an insn rtx that performs a logical not (test != 0) on the src_reg
+  // and stores the result in dst_reg.
   rtx make_not_reg_insn (rtx dst_reg, rtx src_reg) const;
 
   // Create an insn rtx that inverts the ccreg.
@@ -907,12 +911,32 @@
 rtx
 sh_treg_combine::make_not_reg_insn (rtx dst_reg, rtx src_reg) const
 {
-  // This will to go through expanders and may output multiple insns
-  // for multi-word regs.
+  // On SH we can do only SImode and DImode comparisons.
+  if (! (GET_MODE (src_reg) == SImode || GET_MODE (src_reg) == DImode))
+    return NULL;
+
+  // On SH we can store the ccreg into an SImode or DImode reg only.
+  if (! (GET_MODE (dst_reg) == SImode || GET_MODE (dst_reg) == DImode))
+    return NULL;
+
   start_sequence ();
-  expand_simple_unop (GET_MODE (dst_reg), NOT, src_reg, dst_reg, 0);
+
+  emit_insn (gen_rtx_SET (VOIDmode, m_ccreg,
+			  gen_rtx_fmt_ee (EQ, SImode, src_reg, const0_rtx)));
+
+  if (GET_MODE (dst_reg) == SImode)
+    emit_move_insn (dst_reg, m_ccreg);
+  else if (GET_MODE (dst_reg) == DImode)
+    {
+      emit_move_insn (gen_lowpart (SImode, dst_reg), m_ccreg);
+      emit_move_insn (gen_highpart (SImode, dst_reg), const0_rtx);
+    }
+  else
+    gcc_unreachable ();
+
   rtx i = get_insns ();
   end_sequence ();
+
   return i;
 }
 
@@ -1095,7 +1119,12 @@
   // There is one special case though, where an integer comparison
   //     (eq (reg) (const_int 0))
   // can be inverted with a sequence
-  //     (eq (not (reg)) (const_int 0))
+  //     (set (t) (eq (reg) (const_int 0))
+  //     (set (reg) (t))
+  //     (eq (reg) (const_int 0))
+  //
+  // FIXME: On SH2A it might be better to use the nott insn in this case,
+  // i.e. do the try_eliminate_cstores approach instead.
   if (inv_cstore_count != 0 && cstore_count != 0)
     {
       if (make_not_reg_insn (comp_op0, comp_op0) == NULL_RTX)
Index: gcc/testsuite/gcc.target/sh/pr51244-20.c
===================================================================
--- gcc/testsuite/gcc.target/sh/pr51244-20.c	(revision 217823)
+++ gcc/testsuite/gcc.target/sh/pr51244-20.c	(working copy)
@@ -1,15 +1,15 @@
 /* Check that the SH specific sh_treg_combine RTL optimization pass works as
    expected.  On SH2A the expected insns are slightly different, see
-   pr51244-21.c.  */
+   pr51244-20-sh2a.c.  */
 /* { dg-do compile }  */
 /* { dg-options "-O2" } */
 /* { dg-skip-if "" { "sh*-*-*" } { "-m5*" "-m2a*" } { "" } } */
-/* { dg-final { scan-assembler-times "tst" 6 } } */
-/* { dg-final { scan-assembler-times "movt" 1 } } */
+/* { dg-final { scan-assembler-times "tst" 7 } } */
+/* { dg-final { scan-assembler-times "movt" 2 } } */
 /* { dg-final { scan-assembler-times "cmp/eq" 2 } } */
 /* { dg-final { scan-assembler-times "cmp/hi" 4 } } */
 /* { dg-final { scan-assembler-times "cmp/gt" 2 } } */
-/* { dg-final { scan-assembler-times "not\t" 1 } } */
+/* { dg-final { scan-assembler-not "not\t" } } */
 
 
 /* non-SH2A: 2x tst, 1x movt, 2x cmp/eq, 1x cmp/hi
@@ -81,7 +81,7 @@
 }
 
 
-/* 2x tst, 1x cmp/hi, 1x not  */
+/* 3x tst, 1x movt, 1x cmp/hi, 1x not  */
 static inline int
 blk_oversized_queue_5 (int* q)
 {
Index: gcc/testsuite/gcc.target/sh/pr51244-20-sh2a.c
===================================================================
--- gcc/testsuite/gcc.target/sh/pr51244-20-sh2a.c	(revision 217823)
+++ gcc/testsuite/gcc.target/sh/pr51244-20-sh2a.c	(working copy)
@@ -3,12 +3,12 @@
 /* { dg-do compile }  */
 /* { dg-options "-O2" } */
 /* { dg-skip-if "" { "sh*-*-*" } { "*" } { "-m2a*" } } */
-/* { dg-final { scan-assembler-times "tst" 5 } } */
-/* { dg-final { scan-assembler-times "movt" 0 } } */
+/* { dg-final { scan-assembler-times "tst" 6 } } */
+/* { dg-final { scan-assembler-times "movt" 1 } } */
 /* { dg-final { scan-assembler-times "nott" 1 } } */
 /* { dg-final { scan-assembler-times "cmp/eq" 2 } } */
 /* { dg-final { scan-assembler-times "cmp/hi" 4 } } */
 /* { dg-final { scan-assembler-times "cmp/gt" 3 } } */
-/* { dg-final { scan-assembler-times "not\t" 1 } } */
+/* { dg-final { scan-assembler-not "not\t" } } */
 
 #include "pr51244-20.c"
Index: gcc/testsuite/gcc.target/sh/torture/pr63783-1.c
===================================================================
--- gcc/testsuite/gcc.target/sh/torture/pr63783-1.c	(revision 0)
+++ gcc/testsuite/gcc.target/sh/torture/pr63783-1.c	(revision 0)
@@ -0,0 +1,29 @@
+/* { dg-do run }  */
+/* { dg-additional-options "-std=c99" }  */
+
+#include <assert.h>
+
+int decision_result;
+int val;
+int truecount = 0;
+
+static void __attribute__((noinline))
+buggy (int flag)
+{
+  int condition;
+  if(flag == 0)
+    condition = val != 0;
+  else
+    condition = !decision_result;
+  if (condition)
+     truecount++;
+}
+
+int
+main (void)
+{
+  decision_result = 1;
+  buggy(1);
+  assert (truecount == 0);
+  return 0;
+}
Index: gcc/testsuite/gcc.target/sh/torture/pr63783-2.c
===================================================================
--- gcc/testsuite/gcc.target/sh/torture/pr63783-2.c	(revision 0)
+++ gcc/testsuite/gcc.target/sh/torture/pr63783-2.c	(revision 0)
@@ -0,0 +1,29 @@
+/* { dg-do run }  */
+/* { dg-additional-options "-std=c99" }  */
+
+#include <assert.h>
+
+long long decision_result;
+long long val;
+int truecount = 0;
+
+static void __attribute__((noinline))
+buggy (int flag)
+{
+  int condition;
+  if(flag == 0)
+    condition = val != 0;
+  else
+    condition = !decision_result;
+  if (condition)
+     truecount++;
+}
+
+int
+main (void)
+{
+  decision_result = 1;
+  buggy(1);
+  assert (truecount == 0);
+  return 0;
+}

Reply via email to