From 38c821cf31574eb73cf27eec4573fd7e51217fcb Mon Sep 17 00:00:00 2001
From: Jakub Jelinek <jakub@redhat.com>
Date: Fri, 17 May 2013 17:22:24 +0200
Subject: [PATCH] re PR rtl-optimization/57281 (x86_64-linux loop fails to
 terminate at -O3 -m32)

	PR rtl-optimization/57281
	PR rtl-optimization/57300
	* config/i386/i386.md (extendsidi2_1 dead reg splitter): Remove.
	(extendsidi2_1 peephole2s): Add instead 2 new peephole2s, that undo
	what the other splitter did if the registers are dead.

	* gcc.dg/pr57300.c: New test.
	* gcc.c-torture/execute/pr57281.c: New test.

From-SVN: r199018
---
 gcc/ChangeLog                                 |  8 +++
 gcc/config/i386/i386.md                       | 56 +++++++++++++------
 gcc/testsuite/ChangeLog                       |  7 +++
 gcc/testsuite/gcc.c-torture/execute/pr57281.c | 25 +++++++++
 gcc/testsuite/gcc.dg/pr57300.c                | 21 +++++++
 5 files changed, 101 insertions(+), 16 deletions(-)
 create mode 100644 gcc/testsuite/gcc.c-torture/execute/pr57281.c
 create mode 100644 gcc/testsuite/gcc.dg/pr57300.c

diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 4caa40276120..4c406123b5fc 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,11 @@
+2013-05-17  Jakub Jelinek  <jakub@redhat.com>
+
+	PR rtl-optimization/57281
+	PR rtl-optimization/57300
+	* config/i386/i386.md (extendsidi2_1 dead reg splitter): Remove.
+	(extendsidi2_1 peephole2s): Add instead 2 new peephole2s, that undo
+	what the other splitter did if the registers are dead.
+
 2013-05-17  Richard Biener  <rguenther@suse.de>
 
 	* tree-ssa-alias.c (stmt_kills_ref_p_1): Properly compare
diff --git a/gcc/config/i386/i386.md b/gcc/config/i386/i386.md
index 636164920876..ce77f15f0092 100644
--- a/gcc/config/i386/i386.md
+++ b/gcc/config/i386/i386.md
@@ -3332,22 +3332,8 @@
   "!TARGET_64BIT"
   "#")
 
-;; Extend to memory case when source register does die.
-(define_split
-  [(set (match_operand:DI 0 "memory_operand")
-	(sign_extend:DI (match_operand:SI 1 "register_operand")))
-   (clobber (reg:CC FLAGS_REG))
-   (clobber (match_operand:SI 2 "register_operand"))]
-  "(reload_completed
-    && dead_or_set_p (insn, operands[1])
-    && !reg_mentioned_p (operands[1], operands[0]))"
-  [(set (match_dup 3) (match_dup 1))
-   (parallel [(set (match_dup 1) (ashiftrt:SI (match_dup 1) (const_int 31)))
-	      (clobber (reg:CC FLAGS_REG))])
-   (set (match_dup 4) (match_dup 1))]
-  "split_double_mode (DImode, &operands[0], 1, &operands[3], &operands[4]);")
-
-;; Extend to memory case when source register does not die.
+;; Split the memory case.  If the source register doesn't die, it will stay
+;; this way, if it does die, following peephole2s take care of it.
 (define_split
   [(set (match_operand:DI 0 "memory_operand")
 	(sign_extend:DI (match_operand:SI 1 "register_operand")))
@@ -3376,6 +3362,44 @@
   DONE;
 })
 
+;; Peepholes for the case where the source register does die, after
+;; being split with the above splitter.
+(define_peephole2
+  [(set (match_operand:SI 0 "memory_operand")
+	(match_operand:SI 1 "register_operand"))
+   (set (match_operand:SI 2 "register_operand") (match_dup 1))
+   (parallel [(set (match_dup 2)
+		   (ashiftrt:SI (match_dup 2) (const_int 31)))
+	       (clobber (reg:CC FLAGS_REG))])
+   (set (match_operand:SI 3 "memory_operand") (match_dup 2))]
+  "REGNO (operands[1]) != REGNO (operands[2])
+   && peep2_reg_dead_p (2, operands[1])
+   && peep2_reg_dead_p (4, operands[2])
+   && !reg_mentioned_p (operands[2], operands[3])"
+  [(set (match_dup 0) (match_dup 1))
+   (parallel [(set (match_dup 1) (ashiftrt:SI (match_dup 1) (const_int 31)))
+	      (clobber (reg:CC FLAGS_REG))])
+   (set (match_dup 3) (match_dup 1))])
+
+(define_peephole2
+  [(set (match_operand:SI 0 "memory_operand")
+	(match_operand:SI 1 "register_operand"))
+   (parallel [(set (match_operand:SI 2 "register_operand")
+		   (ashiftrt:SI (match_dup 1) (const_int 31)))
+	       (clobber (reg:CC FLAGS_REG))])
+   (set (match_operand:SI 3 "memory_operand") (match_dup 2))]
+  "/* cltd is shorter than sarl $31, %eax */
+   !optimize_function_for_size_p (cfun)
+   && true_regnum (operands[1]) == AX_REG
+   && true_regnum (operands[2]) == DX_REG
+   && peep2_reg_dead_p (2, operands[1])
+   && peep2_reg_dead_p (3, operands[2])
+   && !reg_mentioned_p (operands[2], operands[3])"
+  [(set (match_dup 0) (match_dup 1))
+   (parallel [(set (match_dup 1) (ashiftrt:SI (match_dup 1) (const_int 31)))
+	      (clobber (reg:CC FLAGS_REG))])
+   (set (match_dup 3) (match_dup 1))])
+
 ;; Extend to register case.  Optimize case where source and destination
 ;; registers match and cases where we can use cltd.
 (define_split
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index b2ec2636c7a5..599bcd159a63 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,10 @@
+2013-05-17  Jakub Jelinek  <jakub@redhat.com>
+
+	PR rtl-optimization/57281
+	PR rtl-optimization/57300
+	* gcc.dg/pr57300.c: New test.
+	* gcc.c-torture/execute/pr57281.c: New test.
+
 2013-05-17  Paolo Carlini  <paolo.carlini@oracle.com>
 
 	PR c++/18126
diff --git a/gcc/testsuite/gcc.c-torture/execute/pr57281.c b/gcc/testsuite/gcc.c-torture/execute/pr57281.c
new file mode 100644
index 000000000000..db3db10d9e75
--- /dev/null
+++ b/gcc/testsuite/gcc.c-torture/execute/pr57281.c
@@ -0,0 +1,25 @@
+/* PR rtl-optimization/57281 */
+
+int a = 1, b, d, *e = &d;
+long long c, *g = &c;
+volatile long long f;
+
+int
+foo (int h)
+{
+  int j = *g = b;
+  return h == 0 ? j : 0;
+}
+
+int
+main ()
+{
+  int h = a;
+  for (; b != -20; b--)
+    {
+      (int) f;
+      *e = 0;
+      *e = foo (h);
+    }
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.dg/pr57300.c b/gcc/testsuite/gcc.dg/pr57300.c
new file mode 100644
index 000000000000..13a272de59fe
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr57300.c
@@ -0,0 +1,21 @@
+/* PR rtl-optimization/57300 */
+/* { dg-do run } */
+/* { dg-options "-O3" } */
+/* { dg-additional-options "-msse2" { target sse2_runtime } } */
+
+extern void abort (void);
+int a, b, d[10];
+long long c;
+
+int
+main ()
+{
+  int e;
+  for (e = 0; e < 10; e++)
+    d[e] = 1;
+  if (d[0])
+    c = a = (b == 0 || 1 % b);
+  if (a != 1)
+    abort ();
+  return 0;
+}
-- 
GitLab