Index: ChangeLog
===================================================================
--- ChangeLog	(revision 174424)
+++ ChangeLog	(working copy)
@@ -1,3 +1,10 @@
+2011-05-30  Ira Rosen  <ira.rosen@linaro.org>
+
+	PR tree-optimization/49199
+	* tree-vect-loop.c (vect_is_slp_reduction): Check that the
+	non-reduction operands are either defined in the loop or
+	by induction.
+
 2011-05-29  Xinliang David Li  <davidxl@google.com>
 
 	* opts-global.c (handle_common_deferred_options): Handle new options.
Index: testsuite/gcc.dg/vect/no-scevccp-pr49199.c
===================================================================
--- testsuite/gcc.dg/vect/no-scevccp-pr49199.c	(revision 0)
+++ testsuite/gcc.dg/vect/no-scevccp-pr49199.c	(revision 0)
@@ -0,0 +1,18 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target vect_int } */
+
+int const_bar (void) __attribute__ ((__const__));
+int pure_bar (void) __attribute__ ((__pure__));
+
+int foo (void)
+{
+  int i = 0, x = 0;
+  for (; i < 100; i++)
+    {
+	x += const_bar ();
+	x += pure_bar ();
+    }
+  return x;
+}
+
+/* { dg-final { cleanup-tree-dump "vect" } } */
Index: testsuite/gcc.dg/vect/vect.exp
===================================================================
--- testsuite/gcc.dg/vect/vect.exp	(revision 174424)
+++ testsuite/gcc.dg/vect/vect.exp	(working copy)
@@ -176,6 +176,12 @@ dg-runtest [lsort [glob -nocomplain $srcdir/$subdi
 # -fno-tree-scev-cprop
 set DEFAULT_VECTCFLAGS $SAVED_DEFAULT_VECTCFLAGS
 lappend DEFAULT_VECTCFLAGS "-fno-tree-scev-cprop"
+dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/no-scevccp-pr*.\[cS\]]]  \
+        "" $DEFAULT_VECTCFLAGS
+
+# -fno-tree-scev-cprop
+set DEFAULT_VECTCFLAGS $SAVED_DEFAULT_VECTCFLAGS
+lappend DEFAULT_VECTCFLAGS "-fno-tree-scev-cprop"
 dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/no-scevccp-outer-*.\[cS\]]]  \
         "" $DEFAULT_VECTCFLAGS
 
Index: testsuite/ChangeLog
===================================================================
--- testsuite/ChangeLog	(revision 174424)
+++ testsuite/ChangeLog	(working copy)
@@ -1,3 +1,10 @@
+2011-05-30  Ira Rosen  <ira.rosen@linaro.org>
+
+	PR tree-optimization/49199
+	* gcc.dg/vect/no-scevccp-pr49199.c: New test.
+	* gcc.dg/vect/vect.exp: Run no-scevccp-pr* tests with
+	-fno-tree-scev-cprop.
+
 2011-05-29  Janus Weil  <janus@gcc.gnu.org>
 
 	PR fortran/47601
Index: tree-vect-loop.c
===================================================================
--- tree-vect-loop.c	(revision 174424)
+++ tree-vect-loop.c	(working copy)
@@ -1700,7 +1700,7 @@ vect_is_slp_reduction (loop_vec_info loop_info, gi
   struct loop *loop = (gimple_bb (phi))->loop_father;
   struct loop *vect_loop = LOOP_VINFO_LOOP (loop_info);
   enum tree_code code;
-  gimple current_stmt = NULL, use_stmt = NULL, first;
+  gimple current_stmt = NULL, use_stmt = NULL, first, next_stmt;
   stmt_vec_info use_stmt_info, current_stmt_info;
   tree lhs;
   imm_use_iterator imm_iter;
@@ -1778,36 +1778,92 @@ vect_is_slp_reduction (loop_vec_info loop_info, gi
   if (!found || use_stmt != phi || size < 2)
     return false;
 
-  /* Save the chain for further analysis in SLP detection.  */
-  first = GROUP_FIRST_ELEMENT (vinfo_for_stmt (current_stmt));
-  VEC_safe_push (gimple, heap, LOOP_VINFO_REDUCTION_CHAINS (loop_info), first);
-  GROUP_SIZE (vinfo_for_stmt (first)) = size;
-
   /* Swap the operands, if needed, to make the reduction operand be the second
      operand.  */
   lhs = PHI_RESULT (phi);
-  current_stmt = first;
-  while (current_stmt)
+  next_stmt = GROUP_FIRST_ELEMENT (vinfo_for_stmt (current_stmt));
+  while (next_stmt)
     {
-      if (get_gimple_rhs_class (code) == GIMPLE_BINARY_RHS
-          && gimple_assign_rhs2 (current_stmt) != lhs)
-        {
-          if (vect_print_dump_info (REPORT_DETAILS))
-            {
-              fprintf (vect_dump, "swapping oprnds: ");
-              print_gimple_stmt (vect_dump, current_stmt, 0, TDF_SLIM);
-            }
+      if (get_gimple_rhs_class (code) == GIMPLE_BINARY_RHS)
+	{
+          if (gimple_assign_rhs2 (next_stmt) == lhs)
+	    {
+	      tree op = gimple_assign_rhs1 (next_stmt);
+              gimple def_stmt = NULL;
 
-          swap_tree_operands (current_stmt,
-			      gimple_assign_rhs1_ptr (current_stmt),
-                              gimple_assign_rhs2_ptr (current_stmt));
-          mark_symbols_for_renaming (current_stmt);
+              if (TREE_CODE (op) == SSA_NAME)
+                def_stmt = SSA_NAME_DEF_STMT (op);
+
+	      /* Check that the other def is either defined in the loop
+		 ("vect_internal_def"), or it's an induction (defined by a
+		 loop-header phi-node).  */
+	      if (code == COND_EXPR
+                  || (def_stmt
+		      && flow_bb_inside_loop_p (loop, gimple_bb (def_stmt))
+                      && (is_gimple_assign (def_stmt)
+                          || is_gimple_call (def_stmt)
+                          || STMT_VINFO_DEF_TYPE (vinfo_for_stmt (def_stmt))
+                              == vect_induction_def
+                          || (gimple_code (def_stmt) == GIMPLE_PHI
+                              && STMT_VINFO_DEF_TYPE (vinfo_for_stmt (def_stmt))
+                                  == vect_internal_def
+                              && !is_loop_header_bb_p (gimple_bb (def_stmt))))))
+		{
+		  lhs = gimple_assign_lhs (next_stmt);
+		  next_stmt = GROUP_NEXT_ELEMENT (vinfo_for_stmt (next_stmt));
+ 		  continue;
+		}
+
+	      return false;
+	    }
+	  else
+	    {
+              tree op = gimple_assign_rhs2 (next_stmt);
+              gimple def_stmt = NULL;
+
+              if (TREE_CODE (op) == SSA_NAME)
+                def_stmt = SSA_NAME_DEF_STMT (op);
+
+              /* Check that the other def is either defined in the loop
+                 ("vect_internal_def"), or it's an induction (defined by a
+                 loop-header phi-node).  */
+              if (code == COND_EXPR
+                  || (def_stmt
+		      && flow_bb_inside_loop_p (loop, gimple_bb (def_stmt))
+                      && (is_gimple_assign (def_stmt)
+                          || is_gimple_call (def_stmt)
+                          || STMT_VINFO_DEF_TYPE (vinfo_for_stmt (def_stmt))
+                              == vect_induction_def
+                          || (gimple_code (def_stmt) == GIMPLE_PHI
+                              && STMT_VINFO_DEF_TYPE (vinfo_for_stmt (def_stmt))
+                                  == vect_internal_def
+                              && !is_loop_header_bb_p (gimple_bb (def_stmt))))))
+		{
+		  if (vect_print_dump_info (REPORT_DETAILS))
+		    {
+		      fprintf (vect_dump, "swapping oprnds: ");
+		      print_gimple_stmt (vect_dump, next_stmt, 0, TDF_SLIM);
+		    }
+
+		  swap_tree_operands (next_stmt,
+			      gimple_assign_rhs1_ptr (next_stmt),
+                              gimple_assign_rhs2_ptr (next_stmt));
+		  mark_symbols_for_renaming (next_stmt);
+		}
+	      else
+		return false;
+	    }
         }
 
-      lhs = gimple_assign_lhs (current_stmt);
-      current_stmt = GROUP_NEXT_ELEMENT (vinfo_for_stmt (current_stmt));
+      lhs = gimple_assign_lhs (next_stmt);
+      next_stmt = GROUP_NEXT_ELEMENT (vinfo_for_stmt (next_stmt));
     }
 
+  /* Save the chain for further analysis in SLP detection.  */
+  first = GROUP_FIRST_ELEMENT (vinfo_for_stmt (current_stmt));
+  VEC_safe_push (gimple, heap, LOOP_VINFO_REDUCTION_CHAINS (loop_info), first);
+  GROUP_SIZE (vinfo_for_stmt (first)) = size;
+
   return true;
 }
 
