Patchwork 11 backports from the trunk to 4.5 branch

login
register
mail settings
Submitter Jakub Jelinek
Date July 19, 2011, 1:13 p.m.
Message ID <20110719131359.GC2687@tyan-ft48-01.lab.bos.redhat.com>
Download mbox | patch
Permalink /patch/105474/
State New
Headers show

Comments

Jakub Jelinek - July 19, 2011, 1:13 p.m.
Hi!

I've bootstrapped/regtested on 4.5 branch on x86_64-linux and i686-linux following
patches and committed to the branch.  Will backport those that are needed
for 4.4 also soon.

	Jakub
2011-07-19  Jakub Jelinek  <jakub@redhat.com>

	Backport from mainline
	2011-05-18  Jakub Jelinek  <jakub@redhat.com>

	PR tree-optimization/49039
	* tree-vrp.c (extract_range_from_binary_expr): For
	MIN_EXPR <~[a, b], ~[c, d]> and MAX_EXPR <~[a, b], ~[c, d]>
	return ~[MAX_EXPR <a, c>, MIN_EXPR <b, d>].

	* gcc.c-torture/execute/pr49039.c: New test.
	* gcc.dg/tree-ssa/pr49039.c: New test.
	* g++.dg/torture/pr49039.C: New test.
2011-07-19  Jakub Jelinek  <jakub@redhat.com>

	Backport from mainline
	2011-05-23  Jakub Jelinek  <jakub@redhat.com>

	PR middle-end/48973
	* expr.c (expand_expr_real_2) <case LT_EXPR>: If do_store_flag
	failed and the comparison has a single bit signed type, use
	constm1_rtx instead of const1_rtx for true value.
	(do_store_flag): If ops->type is single bit signed type, disable
	signel bit test optimization and pass -1 instead of 1 as last
	parameter to emit_store_flag_force.

	* gcc.c-torture/execute/pr48973-1.c: New test.
	* gcc.c-torture/execute/pr48973-2.c: New test.

--- gcc/expr.c	(revision 174059)
+++ gcc/expr.c	(revision 174060)
@@ -8105,7 +8105,10 @@ expand_expr_real_2 (sepops ops, rtx targ
       op1 = gen_label_rtx ();
       jumpifnot_1 (code, treeop0, treeop1, op1, -1);
 
-      emit_move_insn (target, const1_rtx);
+      if (TYPE_PRECISION (type) == 1 && !TYPE_UNSIGNED (type))
+	emit_move_insn (target, constm1_rtx);
+      else
+	emit_move_insn (target, const1_rtx);
 
       emit_label (op1);
       return target;
@@ -10050,7 +10053,8 @@ do_store_flag (sepops ops, rtx target, e
 
   if ((code == NE || code == EQ)
       && TREE_CODE (arg0) == BIT_AND_EXPR && integer_zerop (arg1)
-      && integer_pow2p (TREE_OPERAND (arg0, 1)))
+      && integer_pow2p (TREE_OPERAND (arg0, 1))
+      && (TYPE_PRECISION (ops->type) != 1 || TYPE_UNSIGNED (ops->type)))
     {
       tree type = lang_hooks.types.type_for_mode (mode, unsignedp);
       return expand_expr (fold_single_bit_test (loc,
@@ -10070,7 +10074,9 @@ do_store_flag (sepops ops, rtx target, e
 
   /* Try a cstore if possible.  */
   return emit_store_flag_force (target, code, op0, op1,
-			        operand_mode, unsignedp, 1);
+				operand_mode, unsignedp,
+				(TYPE_PRECISION (ops->type) == 1
+				 && !TYPE_UNSIGNED (ops->type)) ? -1 : 1);
 }
 
 
--- gcc/testsuite/gcc.c-torture/execute/pr48973-1.c	(revision 0)
+++ gcc/testsuite/gcc.c-torture/execute/pr48973-1.c	(revision 174060)
@@ -0,0 +1,20 @@
+/* PR middle-end/48973 */
+
+extern void abort (void);
+struct S { int f : 1; } s;
+int v = -1;
+
+void
+foo (unsigned int x)
+{
+  if (x != -1U)
+    abort ();
+}
+
+int
+main ()
+{
+  s.f = (v & 1) > 0;
+  foo (s.f);
+  return 0;
+}
--- gcc/testsuite/gcc.c-torture/execute/pr48973-2.c	(revision 0)
+++ gcc/testsuite/gcc.c-torture/execute/pr48973-2.c	(revision 174060)
@@ -0,0 +1,14 @@
+/* PR middle-end/48973 */
+
+extern void abort (void);
+struct S { int f : 1; } s;
+int v = -1;
+
+int
+main ()
+{
+  s.f = v < 0;
+  if ((unsigned int) s.f != -1U)
+    abort ();
+  return 0;
+}
2011-07-19  Jakub Jelinek  <jakub@redhat.com>

	Backport from mainline
	2011-05-23  Jakub Jelinek  <jakub@redhat.com>

	PR c/49120
	* c-decl.c (start_decl): Convert expr to void_type_node.

	* gcc.dg/pr49120.c: New test.

--- gcc/c-decl.c	(revision 174080)
+++ gcc/c-decl.c	(revision 174081)
@@ -3942,7 +3942,7 @@ start_decl (struct c_declarator *declara
     return 0;
 
   if (expr)
-    add_stmt (expr);
+    add_stmt (fold_convert (void_type_node, expr));
 
   if (TREE_CODE (decl) != FUNCTION_DECL && MAIN_NAME_P (DECL_NAME (decl)))
     warning (OPT_Wmain, "%q+D is usually a function", decl);
--- gcc/testsuite/gcc.dg/pr49120.c	(revision 0)
+++ gcc/testsuite/gcc.dg/pr49120.c	(revision 174081)
@@ -0,0 +1,11 @@
+/* PR c/49120 */
+/* { dg-do compile } */
+/* { dg-options "-Wall" } */
+
+int
+main ()
+{
+  int a = 1;
+  int c = ({ char b[a + 1]; b[0] = 0; b[0]; });
+  return c;
+}
2011-07-19  Jakub Jelinek  <jakub@redhat.com>

	Backport from mainline
	2011-05-26  Jakub Jelinek  <jakub@redhat.com>

	PR tree-optimization/49161
	* tree-vrp.c (struct case_info): New type.
	(compare_case_labels): Sort case_info structs instead of
	trees, and not primarily by CASE_LABEL uids but by
	label_for_block indexes.
	(find_switch_asserts): Put case labels into struct case_info
	array instead of TREE_VEC, adjust sorting, compare label_for_block
	values instead of CASE_LABELs.

	* gcc.c-torture/execute/pr49161.c: New test.

--- gcc/tree-vrp.c	(revision 174269)
+++ gcc/tree-vrp.c	(revision 174270)
@@ -4673,28 +4673,35 @@ find_conditional_asserts (basic_block bb
   return need_assert;
 }
 
-/* Compare two case labels sorting first by the destination label uid
+struct case_info
+{
+  tree expr;
+  basic_block bb;
+};
+
+/* Compare two case labels sorting first by the destination bb index
    and then by the case value.  */
 
 static int
 compare_case_labels (const void *p1, const void *p2)
 {
-  const_tree const case1 = *(const_tree const*)p1;
-  const_tree const case2 = *(const_tree const*)p2;
-  unsigned int uid1 = DECL_UID (CASE_LABEL (case1));
-  unsigned int uid2 = DECL_UID (CASE_LABEL (case2));
+  const struct case_info *ci1 = (const struct case_info *) p1;
+  const struct case_info *ci2 = (const struct case_info *) p2;
+  int idx1 = ci1->bb->index;
+  int idx2 = ci2->bb->index;
 
-  if (uid1 < uid2)
+  if (idx1 < idx2)
     return -1;
-  else if (uid1 == uid2)
+  else if (idx1 == idx2)
     {
       /* Make sure the default label is first in a group.  */
-      if (!CASE_LOW (case1))
+      if (!CASE_LOW (ci1->expr))
 	return -1;
-      else if (!CASE_LOW (case2))
+      else if (!CASE_LOW (ci2->expr))
 	return 1;
       else
-        return tree_int_cst_compare (CASE_LOW (case1), CASE_LOW (case2));
+	return tree_int_cst_compare (CASE_LOW (ci1->expr),
+				     CASE_LOW (ci2->expr));
     }
   else
     return 1;
@@ -4715,8 +4722,8 @@ find_switch_asserts (basic_block bb, gim
   gimple_stmt_iterator bsi;
   tree op;
   edge e;
-  tree vec2;
-  size_t n = gimple_switch_num_labels(last);
+  struct case_info *ci;
+  size_t n = gimple_switch_num_labels (last);
 #if GCC_VERSION >= 4000
   unsigned int idx;
 #else
@@ -4731,36 +4738,38 @@ find_switch_asserts (basic_block bb, gim
     return false;
 
   /* Build a vector of case labels sorted by destination label.  */
-  vec2 = make_tree_vec (n);
+  ci = XNEWVEC (struct case_info, n);
   for (idx = 0; idx < n; ++idx)
-    TREE_VEC_ELT (vec2, idx) = gimple_switch_label (last, idx);
-  qsort (&TREE_VEC_ELT (vec2, 0), n, sizeof (tree), compare_case_labels);
+    {
+      ci[idx].expr = gimple_switch_label (last, idx);
+      ci[idx].bb = label_to_block (CASE_LABEL (ci[idx].expr));
+    }
+  qsort (ci, n, sizeof (struct case_info), compare_case_labels);
 
   for (idx = 0; idx < n; ++idx)
     {
       tree min, max;
-      tree cl = TREE_VEC_ELT (vec2, idx);
+      tree cl = ci[idx].expr;
+      basic_block cbb = ci[idx].bb;
 
       min = CASE_LOW (cl);
       max = CASE_HIGH (cl);
 
       /* If there are multiple case labels with the same destination
 	 we need to combine them to a single value range for the edge.  */
-      if (idx + 1 < n
-	  && CASE_LABEL (cl) == CASE_LABEL (TREE_VEC_ELT (vec2, idx + 1)))
+      if (idx + 1 < n && cbb == ci[idx + 1].bb)
 	{
 	  /* Skip labels until the last of the group.  */
 	  do {
 	    ++idx;
-	  } while (idx < n
-		   && CASE_LABEL (cl) == CASE_LABEL (TREE_VEC_ELT (vec2, idx)));
+	  } while (idx < n && cbb == ci[idx].bb);
 	  --idx;
 
 	  /* Pick up the maximum of the case label range.  */
-	  if (CASE_HIGH (TREE_VEC_ELT (vec2, idx)))
-	    max = CASE_HIGH (TREE_VEC_ELT (vec2, idx));
+	  if (CASE_HIGH (ci[idx].expr))
+	    max = CASE_HIGH (ci[idx].expr);
 	  else
-	    max = CASE_LOW (TREE_VEC_ELT (vec2, idx));
+	    max = CASE_LOW (ci[idx].expr);
 	}
 
       /* Nothing to do if the range includes the default label until we
@@ -4769,7 +4778,7 @@ find_switch_asserts (basic_block bb, gim
 	continue;
 
       /* Find the edge to register the assert expr on.  */
-      e = find_edge (bb, label_to_block (CASE_LABEL (cl)));
+      e = find_edge (bb, cbb);
 
       /* Register the necessary assertions for the operand in the
 	 SWITCH_EXPR.  */
@@ -4787,6 +4796,7 @@ find_switch_asserts (basic_block bb, gim
 	}
     }
 
+  XDELETEVEC (ci);
   return need_assert;
 }
 
--- gcc/testsuite/gcc.c-torture/execute/pr49161.c	(revision 0)
+++ gcc/testsuite/gcc.c-torture/execute/pr49161.c	(revision 174270)
@@ -0,0 +1,46 @@
+/* PR tree-optimization/49161 */
+
+extern void abort (void);
+
+int c;
+
+__attribute__((noinline, noclone)) void
+bar (int x)
+{
+  if (x != c++)
+    abort ();
+}
+
+__attribute__((noinline, noclone)) void
+foo (int x)
+{
+  switch (x)
+    {
+    case 3: goto l1;
+    case 4: goto l2;
+    case 6: goto l3;
+    default: return;
+    }
+l1:
+  goto l4;
+l2:
+  goto l4;
+l3:
+  bar (-1);
+l4:
+  bar (0);
+  if (x != 4)
+    bar (1);
+  if (x != 3)
+    bar (-1);
+  bar (2);
+}
+
+int
+main ()
+{
+  foo (3);
+  if (c != 3)
+    abort ();
+  return 0;
+}
2011-07-19  Jakub Jelinek  <jakub@redhat.com>

	Backport from mainline
	2011-05-26  Jakub Jelinek  <jakub@redhat.com>

	PR c++/49165
	* gimplify.c (shortcut_cond_r): Don't special case
	COND_EXPRs if they have void type on one of their arms.

	* g++.dg/eh/cond5.C: New test.

--- gcc/gimplify.c	(revision 174272)
+++ gcc/gimplify.c	(revision 174273)
@@ -2573,7 +2573,9 @@ shortcut_cond_r (tree pred, tree *true_l
 			   new_locus);
       append_to_statement_list (t, &expr);
     }
-  else if (TREE_CODE (pred) == COND_EXPR)
+  else if (TREE_CODE (pred) == COND_EXPR
+	   && !VOID_TYPE_P (TREE_TYPE (TREE_OPERAND (pred, 1)))
+	   && !VOID_TYPE_P (TREE_TYPE (TREE_OPERAND (pred, 2))))
     {
       location_t new_locus;
 
@@ -2581,7 +2583,10 @@ shortcut_cond_r (tree pred, tree *true_l
 	 if (a)
 	   if (b) goto yes; else goto no;
 	 else
-	   if (c) goto yes; else goto no;  */
+	   if (c) goto yes; else goto no;
+
+	 Don't do this if one of the arms has void type, which can happen
+	 in C++ when the arm is throw.  */
 
       /* Keep the original source location on the first 'if'.  Set the source
 	 location of the ? on the second 'if'.  */
--- gcc/testsuite/g++.dg/eh/cond5.C	(revision 0)
+++ gcc/testsuite/g++.dg/eh/cond5.C	(revision 174273)
@@ -0,0 +1,43 @@
+// PR c++/49165
+// { dg-do run }
+
+extern "C" void abort ();
+
+int
+foo (bool x, int y)
+{
+  if (y < 10 && (x ? true : throw 1))
+    y++;
+  if (y > 20 || (x ? true : throw 2))
+    y++;
+  return y;
+}
+
+int
+main ()
+{
+  if (foo (true, 0) != 2
+      || foo (true, 10) != 11
+      || foo (false, 30) != 31)
+    abort ();
+  try
+    {
+      foo (false, 0);
+      abort ();
+    }
+  catch (int i)
+    {
+      if (i != 1)
+	abort ();
+    }
+  try
+    {
+      foo (false, 10);
+      abort ();
+    }
+  catch (int i)
+    {
+      if (i != 2)
+	abort ();
+    }
+}
2011-07-19  Jakub Jelinek  <jakub@redhat.com>

	Backport from mainline
	2011-05-27  Jakub Jelinek  <jakub@redhat.com>

	PR c++/49165
	* c-common.c (c_common_truthvalue_conversion) <case COND_EXPR>: For
	C++ don't call c_common_truthvalue_conversion on void type arms.

	* g++.dg/eh/cond6.C: New test.

--- gcc/c-common.c	(revision 174349)
+++ gcc/c-common.c	(revision 174350)
@@ -3945,14 +3945,15 @@ c_common_truthvalue_conversion (location
       /* Distribute the conversion into the arms of a COND_EXPR.  */
       if (c_dialect_cxx ())
 	{
+	  tree op1 = TREE_OPERAND (expr, 1);
+	  tree op2 = TREE_OPERAND (expr, 2);
+	  /* In C++ one of the arms might have void type if it is throw.  */
+	  if (!VOID_TYPE_P (TREE_TYPE (op1)))
+	    op1 = c_common_truthvalue_conversion (location, op1);
+	  if (!VOID_TYPE_P (TREE_TYPE (op2)))
+	    op2 = c_common_truthvalue_conversion (location, op2);
 	  expr = fold_build3_loc (location, COND_EXPR, truthvalue_type_node,
-			      TREE_OPERAND (expr, 0),
-			      c_common_truthvalue_conversion (location,
-							      TREE_OPERAND (expr,
-									    1)),
-			      c_common_truthvalue_conversion (location,
-							      TREE_OPERAND (expr,
-									    2)));
+				  TREE_OPERAND (expr, 0), op1, op2);
 	  goto ret;
 	}
       else
--- gcc/testsuite/g++.dg/eh/cond6.C	(revision 0)
+++ gcc/testsuite/g++.dg/eh/cond6.C	(revision 174350)
@@ -0,0 +1,43 @@
+// PR c++/49165
+// { dg-do run }
+
+extern "C" void abort ();
+
+int
+foo (bool x, int y)
+{
+  if (y < 10 && (x ? 1 : throw 1))
+    y++;
+  if (y > 20 || (x ? 1 : throw 2))
+    y++;
+  return y;
+}
+
+int
+main ()
+{
+  if (foo (true, 0) != 2
+      || foo (true, 10) != 11
+      || foo (false, 30) != 31)
+    abort ();
+  try
+    {
+      foo (false, 0);
+      abort ();
+    }
+  catch (int i)
+    {
+      if (i != 1)
+	abort ();
+    }
+  try
+    {
+      foo (false, 10);
+      abort ();
+    }
+  catch (int i)
+    {
+      if (i != 2)
+	abort ();
+    }
+}
2011-07-19  Jakub Jelinek  <jakub@redhat.com>

	Backport from mainline
	2011-07-04  Jakub Jelinek  <jakub@redhat.com>

	PR rtl-optimization/49619
	* combine.c (combine_simplify_rtx): In PLUS -> IOR simplification
	pass VOIDmode as op0_mode to recursive call.

	* gcc.dg/pr49619.c: New test.

--- gcc/combine.c	(revision 175824)
+++ gcc/combine.c	(revision 175825)
@@ -5298,7 +5298,7 @@ combine_simplify_rtx (rtx x, enum machin
 	{
 	  /* Try to simplify the expression further.  */
 	  rtx tor = simplify_gen_binary (IOR, mode, XEXP (x, 0), XEXP (x, 1));
-	  temp = combine_simplify_rtx (tor, mode, in_dest);
+	  temp = combine_simplify_rtx (tor, VOIDmode, in_dest);
 
 	  /* If we could, great.  If not, do not go ahead with the IOR
 	     replacement, since PLUS appears in many special purpose
--- gcc/testsuite/gcc.dg/pr49619.c	(revision 0)
+++ gcc/testsuite/gcc.dg/pr49619.c	(revision 175825)
@@ -0,0 +1,13 @@
+/* PR rtl-optimization/49619 */
+/* { dg-do compile } */
+/* { dg-options "-O -fno-tree-fre" } */
+
+extern int a, b;
+
+void
+foo (int x)
+{
+  a = 2;
+  b = 0;
+  b = (a && ((a = 1, 0 >= b) || (short) (x + (b & x))));
+}
2011-07-19  Jakub Jelinek  <jakub@redhat.com>

	Backport from mainline
	2011-07-07  Jakub Jelinek  <jakub@redhat.com>

	PR middle-end/49640
	* gimplify.c (gimplify_compound_lval): For last 2 ARRAY_*REF
	operands and last COMPONENT_REF operand call gimplify_expr on it
	if non-NULL.

	* gcc.dg/gomp/pr49640.c: New test.

--- gcc/gimplify.c	(revision 175966)
+++ gcc/gimplify.c	(revision 175967)
@@ -2010,8 +2010,14 @@ gimplify_compound_lval (tree *expr_p, gi
 		  ret = MIN (ret, tret);
 		}
 	    }
+	  else
+	    {
+	      tret = gimplify_expr (&TREE_OPERAND (t, 2), pre_p, post_p,
+				    is_gimple_reg, fb_rvalue);
+	      ret = MIN (ret, tret);
+	    }
 
-	  if (!TREE_OPERAND (t, 3))
+	  if (TREE_OPERAND (t, 3) == NULL_TREE)
 	    {
 	      tree elmt_type = TREE_TYPE (TREE_TYPE (TREE_OPERAND (t, 0)));
 	      tree elmt_size = unshare_expr (array_ref_element_size (t));
@@ -2031,11 +2037,17 @@ gimplify_compound_lval (tree *expr_p, gi
 		  ret = MIN (ret, tret);
 		}
 	    }
+	  else
+	    {
+	      tret = gimplify_expr (&TREE_OPERAND (t, 3), pre_p, post_p,
+				    is_gimple_reg, fb_rvalue);
+	      ret = MIN (ret, tret);
+	    }
 	}
       else if (TREE_CODE (t) == COMPONENT_REF)
 	{
 	  /* Set the field offset into T and gimplify it.  */
-	  if (!TREE_OPERAND (t, 2))
+	  if (TREE_OPERAND (t, 2) == NULL_TREE)
 	    {
 	      tree offset = unshare_expr (component_ref_field_offset (t));
 	      tree field = TREE_OPERAND (t, 1);
@@ -2054,6 +2066,12 @@ gimplify_compound_lval (tree *expr_p, gi
 		  ret = MIN (ret, tret);
 		}
 	    }
+	  else
+	    {
+	      tret = gimplify_expr (&TREE_OPERAND (t, 2), pre_p, post_p,
+				    is_gimple_reg, fb_rvalue);
+	      ret = MIN (ret, tret);
+	    }
 	}
     }
 
--- gcc/testsuite/gcc.dg/gomp/pr49640.c	(revision 0)
+++ gcc/testsuite/gcc.dg/gomp/pr49640.c	(revision 175967)
@@ -0,0 +1,29 @@
+/* PR middle-end/49640 */
+/* { dg-do compile } */
+/* { dg-options "-O2 -std=gnu99 -fopenmp" } */
+
+void
+foo (int N, int M, int K, int P, int Q, int R, int i, int j, int k,
+     unsigned char x[P][Q][R], int y[N][M][K])
+{
+  int ii, jj, kk;
+
+#pragma omp parallel for private(ii,jj,kk)
+  for (ii = 0; ii < P; ++ii)
+    for (jj = 0; jj < Q; ++jj)
+      for (kk = 0; kk < R; ++kk)
+	y[i + ii][j + jj][k + kk] = x[ii][jj][kk];
+}
+
+void
+bar (int N, int M, int K, int P, int Q, int R, int i, int j, int k,
+     unsigned char x[P][Q][R], float y[N][M][K], float factor, float zero)
+{
+  int ii, jj, kk;
+
+#pragma omp parallel for private(ii,jj,kk)
+  for (ii = 0; ii < P; ++ii)
+    for (jj = 0; jj < Q; ++jj)
+      for (kk = 0; kk < R; ++kk)
+	y[i + ii][j + jj][k + kk] = factor * x[ii][jj][kk] + zero;
+}
2011-07-19  Jakub Jelinek  <jakub@redhat.com>

	Backport from mainline
	2011-07-07  Jakub Jelinek  <jakub@redhat.com>

	PR c/49644
	* c-typeck.c (build_binary_op): For MULT_EXPR and TRUNC_DIV_EXPR with
	one non-complex and one complex argument, call c_save_expr on both
	operands.

	* gcc.c-torture/execute/pr49644.c: New test.

--- gcc/c-typeck.c	(revision 176003)
+++ gcc/c-typeck.c	(revision 176004)
@@ -10040,6 +10040,7 @@ build_binary_op (location_t location, en
 		{
 		case MULT_EXPR:
 		case TRUNC_DIV_EXPR:
+		  op1 = c_save_expr (op1);
 		  imag = build2 (resultcode, real_type, imag, op1);
 		  /* Fall through.  */
 		case PLUS_EXPR:
@@ -10060,6 +10061,7 @@ build_binary_op (location_t location, en
 	      switch (code)
 		{
 		case MULT_EXPR:
+		  op0 = c_save_expr (op0);
 		  imag = build2 (resultcode, real_type, op0, imag);
 		  /* Fall through.  */
 		case PLUS_EXPR:
--- gcc/testsuite/gcc.c-torture/execute/pr49644.c	(revision 0)
+++ gcc/testsuite/gcc.c-torture/execute/pr49644.c	(revision 176004)
@@ -0,0 +1,16 @@
+/* PR c/49644 */
+
+extern void abort (void);
+
+int
+main ()
+{
+  _Complex double a[12], *c = a, s = 3.0 + 1.0i;
+  double b[12] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 }, *d = b;
+  int i;
+  for (i = 0; i < 6; i++)
+    *c++ = *d++ * s;
+  if (c != a + 6 || d != b + 6)
+    abort ();
+  return 0;
+}
2011-07-19  Jakub Jelinek  <jakub@redhat.com>

	Backport from mainline
	2011-07-07  Jakub Jelinek  <jakub@redhat.com>

	PR c/49644
	* typeck.c (cp_build_binary_op): For MULT_EXPR and TRUNC_DIV_EXPR with
	one non-complex and one complex argument, call save_expr on both
	operands.

	* g++.dg/torture/pr49644.C: New test.

--- gcc/cp/typeck.c	(revision 176005)
+++ gcc/cp/typeck.c	(revision 176006)
@@ -4338,6 +4338,7 @@ cp_build_binary_op (location_t location,
 		{
 		case MULT_EXPR:
 		case TRUNC_DIV_EXPR:
+		  op1 = save_expr (op1);
 		  imag = build2 (resultcode, real_type, imag, op1);
 		  /* Fall through.  */
 		case PLUS_EXPR:
@@ -4356,6 +4357,7 @@ cp_build_binary_op (location_t location,
 	      switch (code)
 		{
 		case MULT_EXPR:
+		  op0 = save_expr (op0);
 		  imag = build2 (resultcode, real_type, op0, imag);
 		  /* Fall through.  */
 		case PLUS_EXPR:
--- gcc/testsuite/g++.dg/torture/pr49644.C	(revision 0)
+++ gcc/testsuite/g++.dg/torture/pr49644.C	(revision 176006)
@@ -0,0 +1,17 @@
+// PR c/49644
+// { dg-do run }
+
+extern "C" void abort ();
+
+int
+main ()
+{
+  _Complex double a[12], *c = a, s = 3.0 + 1.0i;
+  double b[12] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 }, *d = b;
+  int i;
+  for (i = 0; i < 6; i++)
+    *c++ = *d++ * s;
+  if (c != a + 6 || d != b + 6)
+    abort ();
+  return 0;
+}
2011-07-19  Jakub Jelinek  <jakub@redhat.com>

	Backport from mainline
	2011-07-08  Jakub Jelinek  <jakub@redhat.com>

	PR target/49621
	* config/rs6000/rs6000.c (rs6000_emit_vector_cond_expr): Use
	CONST0_RTX (dest_mode) instead of const0_rtx as second operand
	of NE.
	* config/rs6000/vector.md (vector_select_<mode>,
	vector_select_<mode>_uns): Change second operand of NE to
	CONST0_RTX (<MODE>mode) instead of const0_rtx.
	* config/rs6000/altivec.md (*altivec_vsel<mode>,
	*altivec_vsel<mode>_uns): Expect second operand of NE to be
	zero_constant of the corresponding vector mode.
	* config/rs6000/vsx.md (*vsx_xxsel<mode>, *vsx_xxsel<mode>_uns):
	Likewise.

	* gcc.target/powerpc/altivec-34.c: New test.

--- gcc/config/rs6000/vector.md	(revision 176062)
+++ gcc/config/rs6000/vector.md	(revision 176063)
@@ -465,21 +465,21 @@ (define_expand "vector_select_<mode>"
   [(set (match_operand:VEC_L 0 "vlogical_operand" "")
 	(if_then_else:VEC_L
 	 (ne:CC (match_operand:VEC_L 3 "vlogical_operand" "")
-		(const_int 0))
+		(match_dup 4))
 	 (match_operand:VEC_L 2 "vlogical_operand" "")
 	 (match_operand:VEC_L 1 "vlogical_operand" "")))]
   "VECTOR_UNIT_ALTIVEC_OR_VSX_P (<MODE>mode)"
-  "")
+  "operands[4] = CONST0_RTX (<MODE>mode);")
 
 (define_expand "vector_select_<mode>_uns"
   [(set (match_operand:VEC_L 0 "vlogical_operand" "")
 	(if_then_else:VEC_L
 	 (ne:CCUNS (match_operand:VEC_L 3 "vlogical_operand" "")
-		   (const_int 0))
+		   (match_dup 4))
 	 (match_operand:VEC_L 2 "vlogical_operand" "")
 	 (match_operand:VEC_L 1 "vlogical_operand" "")))]
   "VECTOR_UNIT_ALTIVEC_OR_VSX_P (<MODE>mode)"
-  "")
+  "operands[4] = CONST0_RTX (<MODE>mode);")
 
 ;; Expansions that compare vectors producing a vector result and a predicate,
 ;; setting CR6 to indicate a combined status
--- gcc/config/rs6000/rs6000.c	(revision 176062)
+++ gcc/config/rs6000/rs6000.c	(revision 176063)
@@ -16888,7 +16888,7 @@ rs6000_emit_vector_cond_expr (rtx dest, 
       op_false = tmp;
     }
 
-  cond2 = gen_rtx_fmt_ee (NE, cc_mode, mask, const0_rtx);
+  cond2 = gen_rtx_fmt_ee (NE, cc_mode, mask, CONST0_RTX (dest_mode));
   emit_insn (gen_rtx_SET (VOIDmode,
 			  dest,
 			  gen_rtx_IF_THEN_ELSE (dest_mode,
--- gcc/config/rs6000/vsx.md	(revision 176062)
+++ gcc/config/rs6000/vsx.md	(revision 176063)
@@ -674,7 +674,7 @@ (define_insn "*vsx_xxsel<mode>"
   [(set (match_operand:VSX_L 0 "vsx_register_operand" "=<VSr>,?wa")
 	(if_then_else:VSX_L
 	 (ne:CC (match_operand:VSX_L 1 "vsx_register_operand" "<VSr>,wa")
-		(const_int 0))
+		(match_operand:VSX_L 4 "zero_constant" ""))
 	 (match_operand:VSX_L 2 "vsx_register_operand" "<VSr>,wa")
 	 (match_operand:VSX_L 3 "vsx_register_operand" "<VSr>,wa")))]
   "VECTOR_MEM_VSX_P (<MODE>mode)"
@@ -685,7 +685,7 @@ (define_insn "*vsx_xxsel<mode>_uns"
   [(set (match_operand:VSX_L 0 "vsx_register_operand" "=<VSr>,?wa")
 	(if_then_else:VSX_L
 	 (ne:CCUNS (match_operand:VSX_L 1 "vsx_register_operand" "<VSr>,wa")
-		   (const_int 0))
+		   (match_operand:VSX_L 4 "zero_constant" ""))
 	 (match_operand:VSX_L 2 "vsx_register_operand" "<VSr>,wa")
 	 (match_operand:VSX_L 3 "vsx_register_operand" "<VSr>,wa")))]
   "VECTOR_MEM_VSX_P (<MODE>mode)"
--- gcc/config/rs6000/altivec.md	(revision 176062)
+++ gcc/config/rs6000/altivec.md	(revision 176063)
@@ -487,7 +487,7 @@ (define_insn "*altivec_vsel<mode>"
   [(set (match_operand:VM 0 "altivec_register_operand" "=v")
 	(if_then_else:VM
 	 (ne:CC (match_operand:VM 1 "altivec_register_operand" "v")
-		(const_int 0))
+		(match_operand:VM 4 "zero_constant" ""))
 	 (match_operand:VM 2 "altivec_register_operand" "v")
 	 (match_operand:VM 3 "altivec_register_operand" "v")))]
   "VECTOR_MEM_ALTIVEC_P (<MODE>mode)"
@@ -498,7 +498,7 @@ (define_insn "*altivec_vsel<mode>_uns"
   [(set (match_operand:VM 0 "altivec_register_operand" "=v")
 	(if_then_else:VM
 	 (ne:CCUNS (match_operand:VM 1 "altivec_register_operand" "v")
-		   (const_int 0))
+		   (match_operand:VM 4 "zero_constant" ""))
 	 (match_operand:VM 2 "altivec_register_operand" "v")
 	 (match_operand:VM 3 "altivec_register_operand" "v")))]
   "VECTOR_MEM_ALTIVEC_P (<MODE>mode)"
--- gcc/testsuite/gcc.target/powerpc/altivec-34.c	(revision 0)
+++ gcc/testsuite/gcc.target/powerpc/altivec-34.c	(revision 176063)
@@ -0,0 +1,24 @@
+/* PR target/49621 */
+/* { dg-do compile } */
+/* { dg-options "-O2 -maltivec" } */
+
+#include <altivec.h>
+
+int
+foo (void)
+{
+  vector unsigned a, b, c;
+  unsigned k = 1;
+
+  a = (vector unsigned) { 0, 0, 0, 1 };
+  b = c = (vector unsigned) { 0, 0, 0, 0 };
+
+  a = vec_add (a, vec_splats (k));
+  b = vec_add (b, a);
+  c = vec_sel (c, a, b);
+
+  if (vec_any_eq (b, c))
+    return 1;
+
+  return 0;
+}

Patch

--- gcc/tree-vrp.c	(revision 173875)
+++ gcc/tree-vrp.c	(revision 173876)
@@ -1,5 +1,5 @@ 
 /* Support routines for Value Range Propagation (VRP).
-   Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010
+   Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011
    Free Software Foundation, Inc.
    Contributed by Diego Novillo <dnovillo@redhat.com>.
 
@@ -2358,17 +2358,27 @@  extract_range_from_binary_expr (value_ra
 	 op0 + op1 == 0, so we cannot claim that the sum is in ~[0,0].
 	 Note that we are guaranteed to have vr0.type == vr1.type at
 	 this point.  */
-      if (code == PLUS_EXPR && vr0.type == VR_ANTI_RANGE)
+      if (vr0.type == VR_ANTI_RANGE)
 	{
-	  set_value_range_to_varying (vr);
-	  return;
+	  if (code == PLUS_EXPR)
+	    {
+	      set_value_range_to_varying (vr);
+	      return;
+	    }
+	  /* For MIN_EXPR and MAX_EXPR with two VR_ANTI_RANGEs,
+	     the resulting VR_ANTI_RANGE is the same - intersection
+	     of the two ranges.  */
+	  min = vrp_int_const_binop (MAX_EXPR, vr0.min, vr1.min);
+	  max = vrp_int_const_binop (MIN_EXPR, vr0.max, vr1.max);
+	}
+      else
+	{
+	  /* For operations that make the resulting range directly
+	     proportional to the original ranges, apply the operation to
+	     the same end of each range.  */
+	  min = vrp_int_const_binop (code, vr0.min, vr1.min);
+	  max = vrp_int_const_binop (code, vr0.max, vr1.max);
 	}
-
-      /* For operations that make the resulting range directly
-	 proportional to the original ranges, apply the operation to
-	 the same end of each range.  */
-      min = vrp_int_const_binop (code, vr0.min, vr1.min);
-      max = vrp_int_const_binop (code, vr0.max, vr1.max);
 
       /* If both additions overflowed the range kind is still correct.
 	 This happens regularly with subtracting something in unsigned
--- gcc/testsuite/gcc.c-torture/execute/pr49039.c	(revision 0)
+++ gcc/testsuite/gcc.c-torture/execute/pr49039.c	(revision 173876)
@@ -0,0 +1,26 @@ 
+/* PR tree-optimization/49039 */
+extern void abort (void);
+int cnt;
+
+__attribute__((noinline, noclone)) void
+foo (unsigned int x, unsigned int y)
+{
+  unsigned int minv, maxv;
+  if (x == 1 || y == -2U)
+    return;
+  minv = x < y ? x : y;
+  maxv = x > y ? x : y;
+  if (minv == 1)
+    ++cnt;
+  if (maxv == -2U)
+    ++cnt;
+}
+
+int
+main ()
+{
+  foo (-2U, 1);
+  if (cnt != 2)
+    abort ();
+  return 0;
+}
--- gcc/testsuite/gcc.dg/tree-ssa/pr49039.c	(revision 0)
+++ gcc/testsuite/gcc.dg/tree-ssa/pr49039.c	(revision 173876)
@@ -0,0 +1,31 @@ 
+/* PR tree-optimization/49039 */
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-vrp1" } */
+
+extern void bar (void);
+
+void
+foo (unsigned int x, unsigned int y)
+{
+  unsigned int minv, maxv;
+  if (x >= 3 && x <= 6)
+    return;
+  if (y >= 5 && y <= 8)
+    return;
+  minv = x < y ? x : y;
+  maxv = x > y ? x : y;
+  if (minv == 5)
+    bar ();
+  if (minv == 6)
+    bar ();
+  if (maxv == 5)
+    bar ();
+  if (maxv == 6)
+    bar ();
+}
+
+/* { dg-final { scan-tree-dump "Folding predicate minv_\[0-9\]* == 5 to 0" "vrp1" } } */
+/* { dg-final { scan-tree-dump "Folding predicate minv_\[0-9\]* == 6 to 0" "vrp1" } } */
+/* { dg-final { scan-tree-dump "Folding predicate maxv_\[0-9\]* == 5 to 0" "vrp1" } } */
+/* { dg-final { scan-tree-dump "Folding predicate maxv_\[0-9\]* == 6 to 0" "vrp1" } } */
+/* { dg-final { cleanup-tree-dump "vrp1" } } */
--- gcc/testsuite/g++.dg/torture/pr49039.C	(revision 0)
+++ gcc/testsuite/g++.dg/torture/pr49039.C	(revision 173876)
@@ -0,0 +1,76 @@ 
+// PR tree-optimization/49039
+// { dg-do run }
+
+template <class T1, class T2>
+struct pair
+{
+  T1 first;
+  T2 second;
+  pair (const T1 & a, const T2 & b):first (a), second (b) {}
+};
+
+template <class T1, class T2>
+inline pair <T1, T2>
+make_pair (T1 x, T2 y)
+{
+  return pair <T1, T2> (x, y);
+}
+
+typedef __SIZE_TYPE__ size_t;
+struct S
+{
+  const char *Data;
+  size_t Length;
+  static size_t min (size_t a, size_t b) { return a < b ? a : b; }
+  static size_t max (size_t a, size_t b) { return a > b ? a : b; }
+  S () :Data (0), Length (0) { }
+  S (const char *Str) : Data (Str), Length (__builtin_strlen (Str)) {}
+  S (const char *data, size_t length) : Data (data), Length (length) {}
+  bool empty () const { return Length == 0; }
+  size_t size () const { return Length; }
+  S slice (size_t Start, size_t End) const
+  {
+    Start = min (Start, Length);
+    End = min (max (Start, End), Length);
+    return S (Data + Start, End - Start);
+  }
+  pair <S, S> split (char Separator) const
+  {
+    size_t Idx = find (Separator);
+    if (Idx == ~size_t (0))
+      return make_pair (*this, S ());
+    return make_pair (slice (0, Idx), slice (Idx + 1, ~size_t (0)));
+  }
+  size_t find (char C, size_t From = 0) const
+  {
+    for (size_t i = min (From, Length), e = Length; i != e; ++i)
+      if (Data[i] == C)
+	return i;
+    return ~size_t (0);
+  }
+};
+
+void
+Test (const char *arg)
+{
+  S Desc (arg);
+  while (!Desc.empty ())
+    {
+      pair <S, S> Split = Desc.split ('-');
+      S Token = Split.first;
+      Desc = Split.second;
+      if (Token.empty ())
+	continue;
+      Split = Token.split (':');
+      S Specifier = Split.first;
+      if (Specifier.empty ())
+	__builtin_abort ();
+    }
+}
+
+int
+main ()
+{
+  Test ("-");
+  return 0;
+}