From 2caf633d4f8d4281dd428a1cfeac28b92bc9b6f8 Mon Sep 17 00:00:00 2001
From: Uros Bizjak <ubizjak@gmail.com>
Date: Sat, 1 Sep 2012 16:29:45 +0200
Subject: [PATCH] re PR target/46829 (ICE: in spill_failure, at reload1.c:2105
 with -fschedule-insns -fsched-pressure and variadic function)

	PR target/46829
	PR target/46843
	* config/i386/i386.c (ix86_legitimate_combined_insn): New function.
	(TARGET_LEGITIMATE_COMBINED_INSN): New macro.

testsuite/ChangeLog:

	PR target/46829
	PR target/46843
	* gcc.target/i386/pr46829.c: New test.
	* gcc.target/i386/pr46843.c: Ditto.

From-SVN: r190847
---
 gcc/ChangeLog                           |  7 +++
 gcc/config/i386/i386.c                  | 75 +++++++++++++++++++++++++
 gcc/testsuite/ChangeLog                 |  7 +++
 gcc/testsuite/gcc.target/i386/pr46829.c | 18 ++++++
 gcc/testsuite/gcc.target/i386/pr46843.c | 12 ++++
 5 files changed, 119 insertions(+)
 create mode 100644 gcc/testsuite/gcc.target/i386/pr46829.c
 create mode 100644 gcc/testsuite/gcc.target/i386/pr46843.c

diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 545fee025dcd..14b923c1f3a9 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,10 @@
+2012-09-01  Uros Bizjak  <ubizjak@gmail.com>
+
+	PR target/46829
+	PR target/46843
+	* config/i386/i386.c (ix86_legitimate_combined_insn): New function.
+	(TARGET_LEGITIMATE_COMBINED_INSN): New macro.
+
 2012-09-01  Uros Bizjak  <ubizjak@gmail.com>
 
 	* target.def (legitimate_combined_insn): New target hook.
diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c
index c7be00185dc4..e2e1d220302b 100644
--- a/gcc/config/i386/i386.c
+++ b/gcc/config/i386/i386.c
@@ -5545,6 +5545,78 @@ ix86_return_pops_args (tree fundecl, tree funtype, int size)
 
   return 0;
 }
+
+/* Implement the TARGET_LEGITIMATE_COMBINED_INSN hook.  */
+
+static bool
+ix86_legitimate_combined_insn (rtx insn)
+{
+  /* Check operand constraints in case hard registers were propagated
+     into insn pattern.  This check prevents combine pass from
+     generating insn patterns with invalid hard register operands.
+     These invalid insns can eventually confuse reload to error out
+     with a spill failure.  See also PRs 46829 and 46843.  */
+  if ((INSN_CODE (insn) = recog (PATTERN (insn), insn, 0)) >= 0)
+    {
+      int i;
+
+      extract_insn (insn);
+      preprocess_constraints ();
+
+      for (i = 0; i < recog_data.n_operands; i++)
+	{
+	  rtx op = recog_data.operand[i];
+	  enum machine_mode mode = GET_MODE (op);
+	  struct operand_alternative *op_alt;
+	  int offset = 0;
+	  bool win;
+	  int j;
+
+	  /* A unary operator may be accepted by the predicate, but it
+	     is irrelevant for matching constraints.  */
+	  if (UNARY_P (op))
+	    op = XEXP (op, 0);
+
+	  if (GET_CODE (op) == SUBREG)
+	    {
+	      if (REG_P (SUBREG_REG (op))
+		  && REGNO (SUBREG_REG (op)) < FIRST_PSEUDO_REGISTER)
+		offset = subreg_regno_offset (REGNO (SUBREG_REG (op)),
+					      GET_MODE (SUBREG_REG (op)),
+					      SUBREG_BYTE (op),
+					      GET_MODE (op));
+	      op = SUBREG_REG (op);
+	    }
+
+	  if (!(REG_P (op) && HARD_REGISTER_P (op)))
+	    continue;
+
+	  op_alt = recog_op_alt[i];
+
+	  /* Operand has no constraints, anything is OK.  */
+ 	  win = !recog_data.n_alternatives;
+
+	  for (j = 0; j < recog_data.n_alternatives; j++)
+	    {
+	      if (op_alt[j].anything_ok
+		  || (op_alt[j].matches != -1
+		      && operands_match_p
+			  (recog_data.operand[i],
+			   recog_data.operand[op_alt[j].matches]))
+		  || reg_fits_class_p (op, op_alt[j].cl, offset, mode))
+		{
+		  win = true;
+		  break;
+		}
+	    }
+
+	  if (!win)
+	    return false;
+	}
+    }
+
+  return true;
+}
 
 /* Argument support functions.  */
 
@@ -40707,6 +40779,9 @@ ix86_memmodel_check (unsigned HOST_WIDE_INT val)
 #undef TARGET_RETURN_POPS_ARGS
 #define TARGET_RETURN_POPS_ARGS ix86_return_pops_args
 
+#undef TARGET_LEGITIMATE_COMBINED_INSN
+#define TARGET_LEGITIMATE_COMBINED_INSN ix86_legitimate_combined_insn
+
 #undef TARGET_GIMPLIFY_VA_ARG_EXPR
 #define TARGET_GIMPLIFY_VA_ARG_EXPR ix86_gimplify_va_arg
 
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 22fcd065e3c9..c5f88b77415c 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,10 @@
+2012-09-01  Uros Bizjak  <ubizjak@gmail.com>
+
+	PR target/46829
+	PR target/46843
+	* gcc.target/i386/pr46829.c: New test.
+	* gcc.target/i386/pr46843.c: Ditto.
+
 2012-08-31  Paolo Carlini  <paolo.carlini@oracle.com>
 	    Jason Merrill  <jason@redhat.com>
 
diff --git a/gcc/testsuite/gcc.target/i386/pr46829.c b/gcc/testsuite/gcc.target/i386/pr46829.c
new file mode 100644
index 000000000000..d4c04d30fc28
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr46829.c
@@ -0,0 +1,18 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fschedule-insns" } */
+
+struct S
+{
+  int i, j;
+};
+
+extern struct S s[];
+
+extern void bar (int, ...);
+
+void
+foo (int n)
+{
+  while (s[n].i)
+    bar (0, n, s[n].j, s, s[n].i / s[n].j);
+}
diff --git a/gcc/testsuite/gcc.target/i386/pr46843.c b/gcc/testsuite/gcc.target/i386/pr46843.c
new file mode 100644
index 000000000000..3b0d76d134f0
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr46843.c
@@ -0,0 +1,12 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fschedule-insns" } */
+
+void foo (double *d1, double *u1, double *u2, double *d2, int s, int j, int i)
+{
+  int n = 1 << s;
+  double x = 0;
+
+  for (; j < n; j++)
+    x += d1[j] * d2[i];
+  d1[i] = x;
+}