Patchwork 4.6 backports

login
register
mail settings
Submitter Jakub Jelinek
Date April 3, 2013, 6:12 p.m.
Message ID <20130403181239.GJ4201@tucnak.redhat.com>
Download mbox | patch
Permalink /patch/233564/
State New
Headers show

Comments

Jakub Jelinek - April 3, 2013, 6:12 p.m.
Hi!

I've backported 11 patches of mine to 4.6 branch, bootstrapped/regtested
on x86_64-linux and i686-linux, committed.

	Jakub
2013-04-03  Jakub Jelinek  <jakub@redhat.com>

	Backported from mainline
	2012-03-01  Jakub Jelinek  <jakub@redhat.com>

	PR tree-optimization/52445
	* tree-ssa-phiopt.c (struct name_to_bb): Remove ssa_name field,
	add ssa_name_ver, offset and size fields and change store field
	to bool.
	(name_to_bb_hash, name_to_bb_eq): Adjust for the above changes.
	(add_or_mark_expr): Likewise.  Only consider previous stores
	with the same size and offset.
	(nt_init_block): Only look at gimple_assign_single_p stmts,
	doesn't look at rhs2.

	* gcc.dg/pr52445.c: New test.
2013-04-03  Jakub Jelinek  <jakub@redhat.com>

	Backported from mainline
	2012-03-22  Jakub Jelinek  <jakub@redhat.com>

	PR middle-end/52547
	* tree-nested.c (convert_tramp_reference_stmt): Call declare_vars
	on any new_local_var_chain vars declared during recursing on
	GIMPLE_OMP_PARALLEL or GIMPLE_OMP_TASK body.

	* testsuite/libgomp.c/pr52547.c: New test.

--- gcc/tree-nested.c	(revision 185706)
+++ gcc/tree-nested.c	(revision 185707)
@@ -1954,6 +1954,7 @@ static tree
 convert_tramp_reference_stmt (gimple_stmt_iterator *gsi, bool *handled_ops_p,
 			      struct walk_stmt_info *wi)
 {
+  struct nesting_info *info = (struct nesting_info *) wi->info;
   gimple stmt = gsi_stmt (*gsi);
 
   switch (gimple_code (stmt))
@@ -1966,16 +1967,33 @@ convert_tramp_reference_stmt (gimple_stm
 	for (i = 0; i < nargs; i++)
 	  walk_tree (gimple_call_arg_ptr (stmt, i), convert_tramp_reference_op,
 		     wi, NULL);
+	break;
+      }
 
-	*handled_ops_p = true;
-	return NULL_TREE;
+    case GIMPLE_OMP_PARALLEL:
+    case GIMPLE_OMP_TASK:
+      {
+	tree save_local_var_chain;
+        walk_gimple_op (stmt, convert_tramp_reference_op, wi);
+	save_local_var_chain = info->new_local_var_chain;
+	info->new_local_var_chain = NULL;
+        walk_body (convert_tramp_reference_stmt, convert_tramp_reference_op,
+		   info, gimple_omp_body (stmt));
+	if (info->new_local_var_chain)
+	  declare_vars (info->new_local_var_chain,
+			gimple_seq_first_stmt (gimple_omp_body (stmt)),
+			false);
+	info->new_local_var_chain = save_local_var_chain;
       }
+      break;
 
     default:
+      *handled_ops_p = false;
+      return NULL_TREE;
       break;
     }
 
-  *handled_ops_p = false;
+  *handled_ops_p = true;
   return NULL_TREE;
 }
 
--- libgomp/testsuite/libgomp.c/pr52547.c	(revision 0)
+++ libgomp/testsuite/libgomp.c/pr52547.c	(revision 185707)
@@ -0,0 +1,36 @@
+/* PR middle-end/52547 */
+/* { dg-do run } */
+
+extern void abort (void);
+
+__attribute__((noinline, noclone)) int
+baz (int *x, int (*fn) (int *))
+{
+  return fn (x);
+}
+
+__attribute__((noinline, noclone)) int
+foo (int x, int *y)
+{
+  int i, e = 0;
+#pragma omp parallel for reduction(|:e)
+  for (i = 0; i < x; ++i)
+    {
+      __label__ lab;
+      int bar (int *z) { return z - y; }
+      if (baz (&y[i], bar) != i)
+	e |= 1;
+    }
+  return e;
+}
+
+int
+main ()
+{
+  int a[100], i;
+  for (i = 0; i < 100; i++)
+    a[i] = i;
+  if (foo (100, a))
+    abort ();
+  return 0;
+}
2013-04-03  Jakub Jelinek  <jakub@redhat.com>

	Backported from mainline
	2012-05-03  Jakub Jelinek  <jakub@redhat.com>
 
	PR debug/53174
	* tree-predcom.c (remove_stmt): Call reset_debug_uses on stmts being
	removed.

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

--- gcc/tree-predcom.c	(revision 187086)
+++ gcc/tree-predcom.c	(revision 187087)
@@ -1707,6 +1707,7 @@ remove_stmt (gimple stmt)
     {
       name = PHI_RESULT (stmt);
       next = single_nonlooparound_use (name);
+      reset_debug_uses (stmt);
       psi = gsi_for_stmt (stmt);
       remove_phi_node (&psi, true);
 
@@ -1728,6 +1729,7 @@ remove_stmt (gimple stmt)
       gcc_assert (TREE_CODE (name) == SSA_NAME);
 
       next = single_nonlooparound_use (name);
+      reset_debug_uses (stmt);
 
       mark_virtual_ops_for_renaming (stmt);
       gsi_remove (&bsi, true);
--- gcc/testsuite/gcc.dg/pr53174.c	(revision 0)
+++ gcc/testsuite/gcc.dg/pr53174.c	(revision 187087)
@@ -0,0 +1,67 @@
+/* PR debug/53174 */
+/* { dg-do compile } */
+/* { dg-options "-Ofast -g" } */
+
+int w, h;
+
+void
+bar (float (*x)[4], int y, int z)
+{
+  int a, b, c, d, e, f, g;
+
+  a = 2;
+  b = 2;
+  c = 274;
+  d = 274;
+  if (!z)
+    a = 12;
+  if (!y)
+    b = 12;
+  if (z + 266 >= h - 2)
+    c = 8 + h - z;
+  if (y + 266 >= w - 2)
+    d = 8 + w - y;
+  for (e = a; e < c; e++)
+    for (f = b, g = e * 276 + f; f < d; f++, g++)
+      {
+	float (*h)[4] = x + (g - 277);
+	float k = (*h)[0];
+	float l = (*h)[1];
+	float m = (*h)[2];
+	h++;
+	k += (*h)[0];
+	l += (*h)[1];
+	m += (*h)[2];
+	h++;
+	k += (*h)[0];
+	l += (*h)[1];
+	m += (*h)[2];
+	h += 274;
+	k += (*h)[0];
+	l += (*h)[1];
+	m += (*h)[2];
+	h += 2;
+	k += (*h)[0];
+	l += (*h)[1];
+	m += (*h)[2];
+	h += 274;
+	k += (*h)[0];
+	l += (*h)[1];
+	m += (*h)[2];
+	h++;
+	k += (*h)[0];
+	l += (*h)[1];
+	m += (*h)[2];
+	h++;
+	k += (*h)[0];
+	l += (*h)[1];
+	m += (*h)[2];
+	k *= 0.125f;
+	l *= 0.125f;
+	m *= 0.125f;
+	k = k + (x[g][1] - l);
+	m = m + (x[g][1] - l);
+	x[g][0] = k;
+	x[g][2] = m;
+      }
+}
2013-04-03  Jakub Jelinek  <jakub@redhat.com>

	Backported from mainline
	2012-08-24  Jakub Jelinek  <jakub@redhat.com>

	PR c/54363
	* gimplify.c (optimize_compound_literals_in_ctor): Only recurse
	if init is a CONSTRUCTOR.

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

--- gcc/gimplify.c	(revision 190656)
+++ gcc/gimplify.c	(revision 190657)
@@ -3857,7 +3857,8 @@ optimize_compound_literals_in_ctor (tree
 
 	  if (!TREE_ADDRESSABLE (value)
 	      && !TREE_ADDRESSABLE (decl)
-	      && init)
+	      && init
+	      && TREE_CODE (init) == CONSTRUCTOR)
 	    newval = optimize_compound_literals_in_ctor (init);
 	}
       if (newval == value)
--- gcc/testsuite/gcc.dg/pr54363.c	(revision 0)
+++ gcc/testsuite/gcc.dg/pr54363.c	(revision 190657)
@@ -0,0 +1,12 @@
+/* PR c/54363 */
+/* { dg-do compile } */
+/* { dg-options "-std=gnu99" } */
+
+struct S { char **a; };
+
+void
+test (void)
+{
+  struct S b = { .a = (char **) { "a", "b" } }; /* { dg-warning "(initialization|excess elements)" } */
+  struct S c = { .a = (char *[]) { "a", "b" } };
+}
2013-04-03  Jakub Jelinek  <jakub@redhat.com>

	Backported from mainline
	2012-09-05  Jakub Jelinek  <jakub@redhat.com>

	PR middle-end/54486
	* builtins.c (fold_builtin_strspn, fold_builtin_strcspn): Use
	build_int_cst with size_type_node instead of size_int.

	* c-c++-common/pr54486.c: New test.

--- gcc/builtins.c	(revision 190985)
+++ gcc/builtins.c	(revision 190986)
@@ -11890,7 +11890,7 @@ fold_builtin_strspn (location_t loc, tre
       if (p1 && p2)
 	{
 	  const size_t r = strspn (p1, p2);
-	  return size_int (r);
+	  return build_int_cst (size_type_node, r);
 	}
 
       /* If either argument is "", return NULL_TREE.  */
@@ -11935,7 +11935,7 @@ fold_builtin_strcspn (location_t loc, tr
       if (p1 && p2)
 	{
 	  const size_t r = strcspn (p1, p2);
-	  return size_int (r);
+	  return build_int_cst (size_type_node, r);
 	}
 
       /* If the first argument is "", return NULL_TREE.  */
--- gcc/testsuite/c-c++-common/pr54486.c	(revision 0)
+++ gcc/testsuite/c-c++-common/pr54486.c	(revision 190986)
@@ -0,0 +1,32 @@
+/* PR middle-end/54486 */
+/* { dg-do compile } */
+/* { dg-options "-Wformat" } */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+typedef __SIZE_TYPE__ size_t;
+extern int printf (const char *, ...);
+extern size_t strspn (const char *, const char *);
+extern size_t strcspn (const char *, const char *);
+extern size_t strlen (const char *);
+#ifdef __cplusplus
+}
+#endif
+
+void
+foo (void)
+{
+  printf ("%zu\n", strspn ("abc", "abcdefg"));
+  printf ("%zu\n", (size_t) strspn ("abc", "abcdefg"));
+  printf ("%zu\n", __builtin_strspn ("abc", "abcdefg"));
+  printf ("%zu\n", (size_t) __builtin_strspn ("abc", "abcdefg"));
+  printf ("%zu\n", strcspn ("abc", "abcdefg"));
+  printf ("%zu\n", (size_t) strcspn ("abc", "abcdefg"));
+  printf ("%zu\n", __builtin_strcspn ("abc", "abcdefg"));
+  printf ("%zu\n", (size_t) __builtin_strcspn ("abc", "abcdefg"));
+  printf ("%zu\n", strlen ("abc"));
+  printf ("%zu\n", (size_t) strlen ("abc"));
+  printf ("%zu\n", __builtin_strlen ("abc"));
+  printf ("%zu\n", (size_t) __builtin_strlen ("abc"));
+}
2013-04-03  Jakub Jelinek  <jakub@redhat.com>

	Backported from mainline
	2012-10-08  Jakub Jelinek  <jakub@redhat.com>

	PR c++/54858
	* tree.c (cp_tree_equal): Handle FIELD_DECL.

	* g++.dg/template/pr54858.C: New test.

--- gcc/cp/tree.c	(revision 192219)
+++ gcc/cp/tree.c	(revision 192220)
@@ -2559,6 +2559,7 @@ cp_tree_equal (tree t1, tree t2)
 
     case VAR_DECL:
     case CONST_DECL:
+    case FIELD_DECL:
     case FUNCTION_DECL:
     case TEMPLATE_DECL:
     case IDENTIFIER_NODE:
--- gcc/testsuite/g++.dg/template/pr54858.C	(revision 0)
+++ gcc/testsuite/g++.dg/template/pr54858.C	(revision 192220)
@@ -0,0 +1,21 @@
+// PR c++/54858
+// { dg-do compile }
+
+template <int> struct A {};
+template <typename T, T *> struct B {};
+template <typename D> struct C
+{
+  A<0> c0; B<A<0>, &C::c0> d0;	// { dg-error "could not convert template argument" }
+  A<0> c1; B<A<0>, &C::c1> d1;	// { dg-error "could not convert template argument" }
+  A<0> c2; B<A<0>, &C::c2> d2;	// { dg-error "could not convert template argument" }
+  A<0> c3; B<A<0>, &C::c3> d3;	// { dg-error "could not convert template argument" }
+  A<0> c4; B<A<0>, &C::c4> d4;	// { dg-error "could not convert template argument" }
+  A<0> c5; B<A<0>, &C::c5> d5;	// { dg-error "could not convert template argument" }
+  A<0> c6; B<A<0>, &C::c6> d6;	// { dg-error "could not convert template argument" }
+  A<0> c7; B<A<0>, &C::c7> d7;	// { dg-error "could not convert template argument" }
+  A<0> c8; B<A<0>, &C::c8> d8;	// { dg-error "could not convert template argument" }
+  A<0> c9; B<A<0>, &C::c9> d9;	// { dg-error "could not convert template argument" }
+  A<0> ca; B<A<0>, &C::ca> da;	// { dg-error "could not convert template argument" }
+  A<0> cb; B<A<0>, &C::cb> db;	// { dg-error "could not convert template argument" }
+};
+C<int> e;
2013-04-03  Jakub Jelinek  <jakub@redhat.com>

	Backported from mainline
	2013-01-10  Jakub Jelinek  <jakub@redhat.com>

	PR tree-optimization/55921
	* tree-complex.c (expand_complex_asm): New function.
	(expand_complex_operations_1): Call it for GIMPLE_ASM.

--- gcc/tree-complex.c	(revision 195079)
+++ gcc/tree-complex.c	(revision 195080)
@@ -1391,6 +1391,36 @@ expand_complex_comparison (gimple_stmt_i
   update_stmt (stmt);
 }
 
+/* Expand inline asm that sets some complex SSA_NAMEs.  */
+
+static void
+expand_complex_asm (gimple_stmt_iterator *gsi)
+{
+  gimple stmt = gsi_stmt (*gsi);
+  unsigned int i;
+
+  for (i = 0; i < gimple_asm_noutputs (stmt); ++i)
+    {
+      tree link = gimple_asm_output_op (stmt, i);
+      tree op = TREE_VALUE (link);
+      if (TREE_CODE (op) == SSA_NAME
+	  && TREE_CODE (TREE_TYPE (op)) == COMPLEX_TYPE)
+	{
+	  tree type = TREE_TYPE (op);
+	  tree inner_type = TREE_TYPE (type);
+	  tree r = build1 (REALPART_EXPR, inner_type, op);
+	  tree i = build1 (IMAGPART_EXPR, inner_type, op);
+	  gimple_seq list = set_component_ssa_name (op, false, r);
+
+	  if (list)
+	    gsi_insert_seq_after (gsi, list, GSI_CONTINUE_LINKING);
+
+	  list = set_component_ssa_name (op, true, i);
+	  if (list)
+	    gsi_insert_seq_after (gsi, list, GSI_CONTINUE_LINKING);
+	}
+    }
+}
 
 /* Process one statement.  If we identify a complex operation, expand it.  */
 
@@ -1403,6 +1433,12 @@ expand_complex_operations_1 (gimple_stmt
   complex_lattice_t al, bl;
   enum tree_code code;
 
+  if (gimple_code (stmt) == GIMPLE_ASM)
+    {
+      expand_complex_asm (gsi);
+      return;
+    }
+
   lhs = gimple_get_lhs (stmt);
   if (!lhs && gimple_code (stmt) != GIMPLE_COND)
     return;
2013-04-03  Jakub Jelinek  <jakub@redhat.com>

	Backported from mainline
	2013-01-18  Jakub Jelinek  <jakub@redhat.com>

	PR middle-end/56015
	* expr.c (expand_expr_real_2) <case COMPLEX_EXPR>: Handle
	the case where writing real complex part of target modifies
	op1.

	* gfortran.dg/pr56015.f90: New test.

--- gcc/expr.c	(revision 195300)
+++ gcc/expr.c	(revision 195301)
@@ -8860,6 +8860,54 @@ expand_expr_real_2 (sepops ops, rtx targ
 
       if (!target)
 	target = gen_reg_rtx (TYPE_MODE (type));
+      else
+	/* If target overlaps with op1, then either we need to force
+	   op1 into a pseudo (if target also overlaps with op0),
+	   or write the complex parts in reverse order.  */
+	switch (GET_CODE (target))
+	  {
+	  case CONCAT:
+	    if (reg_overlap_mentioned_p (XEXP (target, 0), op1))
+	      {
+		if (reg_overlap_mentioned_p (XEXP (target, 1), op0))
+		  {
+		  complex_expr_force_op1:
+		    temp = gen_reg_rtx (GET_MODE_INNER (GET_MODE (target)));
+		    emit_move_insn (temp, op1);
+		    op1 = temp;
+		    break;
+		  }
+	      complex_expr_swap_order:
+		/* Move the imaginary (op1) and real (op0) parts to their
+		   location.  */
+		write_complex_part (target, op1, true);
+		write_complex_part (target, op0, false);
+
+		return target;
+	      }
+	    break;
+	  case MEM:
+	    temp = adjust_address_nv (target,
+				      GET_MODE_INNER (GET_MODE (target)), 0);
+	    if (reg_overlap_mentioned_p (temp, op1))
+	      {
+		enum machine_mode imode = GET_MODE_INNER (GET_MODE (target));
+		temp = adjust_address_nv (target, imode,
+					  GET_MODE_SIZE (imode));
+		if (reg_overlap_mentioned_p (temp, op0))
+		  goto complex_expr_force_op1;
+		goto complex_expr_swap_order;
+	      }
+	    break;
+	  default:
+	    if (reg_overlap_mentioned_p (target, op1))
+	      {
+		if (reg_overlap_mentioned_p (target, op0))
+		  goto complex_expr_force_op1;
+		goto complex_expr_swap_order;
+	      }
+	    break;
+	  }
 
       /* Move the real (op0) and imaginary (op1) parts to their location.  */
       write_complex_part (target, op0, false);
--- gcc/testsuite/gfortran.dg/pr56015.f90	(revision 0)
+++ gcc/testsuite/gfortran.dg/pr56015.f90	(revision 195301)
@@ -0,0 +1,16 @@
+! PR middle-end/56015
+! { dg-do run }
+! { dg-options "-O3 -ffast-math -fno-inline" }
+
+program pr56015
+  implicit none
+  complex*16 p(10)
+  p(:) = (0.1d0, 0.2d0)
+  p(:) = (0.0d0, 1.0d0) * p(:)
+  call foo (p)
+contains
+  subroutine foo (p)
+    complex*16 p(10)
+    if (any (p .ne. (-0.2d0, 0.1d0))) call abort
+  end subroutine
+end program pr56015
2013-04-03  Jakub Jelinek  <jakub@redhat.com>

	Backported from mainline
	2013-01-25  Jakub Jelinek  <jakub@redhat.com>

	PR tree-optimization/56098
	* tree-ssa-phiopt.c (nt_init_block): Don't call add_or_mark_expr
	for stmts with volatile ops.
	(cond_store_replacement): Don't optimize if assign has volatile ops.
	(cond_if_else_store_replacement_1): Don't optimize if either
	then_assign or else_assign have volatile ops.

	* gcc.dg/pr56098-1.c: New test.

--- gcc/tree-ssa-phiopt.c	(revision 195474)
+++ gcc/tree-ssa-phiopt.c	(revision 195475)
@@ -1160,7 +1160,7 @@ nt_init_block (struct dom_walk_data *dat
     {
       gimple stmt = gsi_stmt (gsi);
 
-      if (gimple_assign_single_p (stmt))
+      if (gimple_assign_single_p (stmt) && !gimple_has_volatile_ops (stmt))
 	{
 	  add_or_mark_expr (bb, gimple_assign_lhs (stmt), nontrap_set, true);
 	  add_or_mark_expr (bb, gimple_assign_rhs1 (stmt), nontrap_set, false);
@@ -1237,7 +1237,8 @@ cond_store_replacement (basic_block midd
 
   /* Check if middle_bb contains of only one store.  */
   if (!assign
-      || !gimple_assign_single_p (assign))
+      || !gimple_assign_single_p (assign)
+      || gimple_has_volatile_ops (assign))
     return false;
 
   locus = gimple_location (assign);
@@ -1333,8 +1334,10 @@ cond_if_else_store_replacement (basic_bl
   /* Check if then_bb and else_bb contain only one store each.  */
   if (then_assign == NULL
       || !gimple_assign_single_p (then_assign)
+      || gimple_has_volatile_ops (then_assign)
       || else_assign == NULL
-      || !gimple_assign_single_p (else_assign))
+      || !gimple_assign_single_p (else_assign)
+      || gimple_has_volatile_ops (else_assign))
     return false;
 
   lhs = gimple_assign_lhs (then_assign);
--- gcc/testsuite/gcc.dg/pr56098-1.c	(revision 0)
+++ gcc/testsuite/gcc.dg/pr56098-1.c	(revision 195475)
@@ -0,0 +1,16 @@
+/* PR tree-optimization/56098 */
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-optimized" } */
+
+volatile int *p;
+
+void
+foo (int x)
+{
+  *p = 1;
+  if (x)
+    *p = 2;
+}
+
+/* { dg-final { scan-tree-dump-not "=\[^\n\r]*\\*p" "optimized" } } */
+/* { dg-final { cleanup-tree-dump "optimized" } } */
2013-04-03  Jakub Jelinek  <jakub@redhat.com>

	Backported from mainline
	2013-02-07  Jakub Jelinek  <jakub@redhat.com>

	PR c++/56239
	* parser.c (cp_parser_token_starts_cast_expression): Renamed to...
	(cp_parser_tokens_start_cast_expression): ... this.  Change parameter
	to cp_parser *, call cp_lexer_peek_token first.  For CPP_OPEN_PAREN,
	return true only if 2nd token isn't CPP_CLOSE_PAREN.
	(cp_parser_cast_expression): Adjust caller.

	* g++.dg/parse/pr56239.C: New test.

--- gcc/cp/parser.c	(revision 195858)
+++ gcc/cp/parser.c	(revision 195859)
@@ -7091,8 +7091,9 @@ cp_parser_delete_expression (cp_parser*
    otherwise.  */
 
 static bool
-cp_parser_token_starts_cast_expression (cp_token *token)
+cp_parser_tokens_start_cast_expression (cp_parser *parser)
 {
+  cp_token *token = cp_lexer_peek_token (parser->lexer);
   switch (token->type)
     {
     case CPP_COMMA:
@@ -7133,6 +7134,12 @@ cp_parser_token_starts_cast_expression (
     case CPP_EOF:
       return false;
 
+    case CPP_OPEN_PAREN:
+      /* In ((type ()) () the last () isn't a valid cast-expression,
+	 so the whole must be parsed as postfix-expression.  */
+      return cp_lexer_peek_nth_token (parser->lexer, 2)->type
+	     != CPP_CLOSE_PAREN;
+
       /* '[' may start a primary-expression in obj-c++.  */
     case CPP_OPEN_SQUARE:
       return c_dialect_objc ();
@@ -7225,8 +7232,7 @@ cp_parser_cast_expression (cp_parser *pa
 	 parenthesized ctor such as `(T ())' that looks like a cast to
 	 function returning T.  */
       if (!cp_parser_error_occurred (parser)
-	  && cp_parser_token_starts_cast_expression (cp_lexer_peek_token
-						     (parser->lexer)))
+	  && cp_parser_tokens_start_cast_expression (parser))
 	{
 	  cp_parser_parse_definitely (parser);
 	  expr = cp_parser_cast_expression (parser,
--- gcc/testsuite/g++.dg/parse/pr56239.C	(revision 0)
+++ gcc/testsuite/g++.dg/parse/pr56239.C	(revision 195859)
@@ -0,0 +1,13 @@
+// PR c++/56239
+// { dg-do compile }
+
+struct S
+{
+  int operator () () { return 0; }
+};
+
+int
+main ()
+{
+  return (S ()) ();
+}
2013-04-03  Jakub Jelinek  <jakub@redhat.com>

	Backported from mainline
	2013-03-06  Jakub Jelinek  <jakub@redhat.com>

	PR tree-optimization/56539
	* tree-tailcall.c (adjust_return_value_with_ops): Use GSI_SAME_STMT
	instead of GSI_CONTINUE_LINKING as last argument to
	force_gimple_operand_gsi.  Adjust function comment.

	* gcc.c-torture/compile/pr56539.c: New test.

--- gcc/tree-tailcall.c	(revision 196510)
+++ gcc/tree-tailcall.c	(revision 196511)
@@ -599,8 +599,8 @@ add_successor_phi_arg (edge e, tree var,
 }
 
 /* Creates a GIMPLE statement which computes the operation specified by
-   CODE, OP0 and OP1 to a new variable with name LABEL and inserts the
-   statement in the position specified by GSI and UPDATE.  Returns the
+   CODE, ACC and OP1 to a new variable with name LABEL and inserts the
+   statement in the position specified by GSI.  Returns the
    tree node of the statement's result.  */
 
 static tree
@@ -622,7 +622,7 @@ adjust_return_value_with_ops (enum tree_
 					    fold_convert (TREE_TYPE (op1), acc),
 					    op1));
       rhs = force_gimple_operand_gsi (&gsi, rhs,
-				      false, NULL, true, GSI_CONTINUE_LINKING);
+				      false, NULL, true, GSI_SAME_STMT);
       stmt = gimple_build_assign (NULL_TREE, rhs);
     }
 
--- gcc/testsuite/gcc.c-torture/compile/pr56539.c	(revision 0)
+++ gcc/testsuite/gcc.c-torture/compile/pr56539.c	(revision 196511)
@@ -0,0 +1,7 @@
+/* PR tree-optimization/56539 */
+
+short
+foo (const char *x, unsigned y)
+{
+  return y > 1 ? (x[y - 1] - '0') + 10 * foo (x, y - 1) : (*x - '0');
+}

Patch

--- gcc/tree-ssa-phiopt.c	(revision 184742)
+++ gcc/tree-ssa-phiopt.c	(revision 184743)
@@ -1122,9 +1122,10 @@  abs_replacement (basic_block cond_bb, ba
    same accesses.  */
 struct name_to_bb
 {
-  tree ssa_name;
+  unsigned int ssa_name_ver;
+  bool store;
+  HOST_WIDE_INT offset, size;
   basic_block bb;
-  unsigned store : 1;
 };
 
 /* The hash table for remembering what we've seen.  */
@@ -1133,23 +1134,26 @@  static htab_t seen_ssa_names;
 /* The set of MEM_REFs which can't trap.  */
 static struct pointer_set_t *nontrap_set;
 
-/* The hash function, based on the pointer to the pointer SSA_NAME.  */
+/* The hash function.  */
 static hashval_t
 name_to_bb_hash (const void *p)
 {
-  const_tree n = ((const struct name_to_bb *)p)->ssa_name;
-  return htab_hash_pointer (n) ^ ((const struct name_to_bb *)p)->store;
+  const struct name_to_bb *n = (const struct name_to_bb *) p;
+  return n->ssa_name_ver ^ (((hashval_t) n->store) << 31)
+         ^ (n->offset << 6) ^ (n->size << 3);
 }
 
-/* The equality function of *P1 and *P2.  SSA_NAMEs are shared, so
-   it's enough to simply compare them for equality.  */
+/* The equality function of *P1 and *P2.  */
 static int
 name_to_bb_eq (const void *p1, const void *p2)
 {
   const struct name_to_bb *n1 = (const struct name_to_bb *)p1;
   const struct name_to_bb *n2 = (const struct name_to_bb *)p2;
 
-  return n1->ssa_name == n2->ssa_name && n1->store == n2->store;
+  return n1->ssa_name_ver == n2->ssa_name_ver
+         && n1->store == n2->store
+         && n1->offset == n2->offset
+         && n1->size == n2->size;
 }
 
 /* We see the expression EXP in basic block BB.  If it's an interesting
@@ -1161,8 +1165,12 @@  static void
 add_or_mark_expr (basic_block bb, tree exp,
 		  struct pointer_set_t *nontrap, bool store)
 {
+  HOST_WIDE_INT size;
+
   if (TREE_CODE (exp) == MEM_REF
-      && TREE_CODE (TREE_OPERAND (exp, 0)) == SSA_NAME)
+      && TREE_CODE (TREE_OPERAND (exp, 0)) == SSA_NAME
+      && host_integerp (TREE_OPERAND (exp, 1), 0)
+      && (size = int_size_in_bytes (TREE_TYPE (exp))) > 0)
     {
       tree name = TREE_OPERAND (exp, 0);
       struct name_to_bb map;
@@ -1172,9 +1180,12 @@  add_or_mark_expr (basic_block bb, tree e
 
       /* Try to find the last seen MEM_REF through the same
          SSA_NAME, which can trap.  */
-      map.ssa_name = name;
+      map.ssa_name_ver = SSA_NAME_VERSION (name);
       map.bb = 0;
       map.store = store;
+      map.offset = tree_low_cst (TREE_OPERAND (exp, 1), 0);
+      map.size = size;
+
       slot = htab_find_slot (seen_ssa_names, &map, INSERT);
       n2bb = (struct name_to_bb *) *slot;
       if (n2bb)
@@ -1197,9 +1208,11 @@  add_or_mark_expr (basic_block bb, tree e
 	  else
 	    {
 	      n2bb = XNEW (struct name_to_bb);
-	      n2bb->ssa_name = name;
+	      n2bb->ssa_name_ver = SSA_NAME_VERSION (name);
 	      n2bb->bb = bb;
 	      n2bb->store = store;
+	      n2bb->offset = map.offset;
+	      n2bb->size = size;
 	      *slot = n2bb;
 	    }
 	}
@@ -1219,13 +1232,10 @@  nt_init_block (struct dom_walk_data *dat
     {
       gimple stmt = gsi_stmt (gsi);
 
-      if (is_gimple_assign (stmt))
+      if (gimple_assign_single_p (stmt))
 	{
 	  add_or_mark_expr (bb, gimple_assign_lhs (stmt), nontrap_set, true);
 	  add_or_mark_expr (bb, gimple_assign_rhs1 (stmt), nontrap_set, false);
-	  if (get_gimple_rhs_num_ops (gimple_assign_rhs_code (stmt)) > 1)
-	    add_or_mark_expr (bb, gimple_assign_rhs2 (stmt), nontrap_set,
-			      false);
 	}
     }
 }
--- gcc/testsuite/gcc.dg/pr52445.c	(revision 0)
+++ gcc/testsuite/gcc.dg/pr52445.c	(revision 184743)
@@ -0,0 +1,15 @@ 
+/* PR tree-optimization/52445 */
+/* { dg-do compile } */
+/* { dg-options "-O2 -ftree-cselim -fdump-tree-cselim" } */
+
+void
+foo (char *buf, unsigned long len)
+{
+  buf[0] = '\n';
+  if (len > 1)
+    buf[1] = '\0';	/* We can't cselim "optimize" this, while
+			   buf[0] doesn't trap, buf[1] could.  */
+}
+
+/* { dg-final { scan-tree-dump-not "cstore\." "cselim" } } */
+/* { dg-final { cleanup-tree-dump "cselim" } } */