[PATCH][4.5] Backport fix for PR45967

Richard Guenther rguenther@suse.de
Wed Mar 2 15:54:00 GMT 2011


This fixes the PTA related miscompile of obfuscated pointer copying.
It is the variant I settled on for trunk after exploring multiple
ideas.  It is quite intrusive but its risks are merely compile-time,
memory-usage and PTA quality regressions (especially not miscompiles).

Bootstrapped and tested on x86_64-unknown-linux-gnu.  I consider
applying this patch after leaving it here for some time to allow
people to double-check.

Richard.

2011-03-02  Richard Guenther  <rguenther@suse.de>

	Backport from mainline
	2011-02-10  Richard Guenther  <rguenther@suse.de>

	* tree-ssa-structalias.c (bitpos_of_field): Use BITS_PER_UNIT, not 8.

	2010-10-18  Richard Guenther  <rguenther@suse.de>

	PR tree-optimization/45967
	* tree-ssa-structalias.c (type_could_have_pointers): Remove.
	(could_have_pointers): Likewise.
	(handle_rhs_call, handle_const_call, handle_pure_call,
	find_func_aliases, intra_create_variable_infos): Remove calls to them.
	(struct fieldoff): Add must_have_pointers field.
	(type_must_have_pointers): New function.
	(field_must_have_pointers): Likewise.
	(push_fields_onto_fieldstack): Remove must_have_pointers_p argument.
	Adjust field merging.
	(create_function_info_for): May-have-pointers of varinfo is
	almost always true.
	(create_variable_info_for_1): Likewise.

	* gcc.dg/torture/pr45967.c: New testcase.
	* gcc.dg/torture/pr45967-2.c: Likewise.
	* gcc.dg/torture/pr45967-3.c: Likewise.
	* gcc.dg/torture/pr39074-2.c: Adjust. 
	* gcc.dg/torture/pta-escape-1.c: Likewise
	* gcc.dg/torture/pta-ptrarith-1.c: Likewise
	* gcc.dg/tree-ssa/pta-callused.c: Likewise
	* gcc.dg/tree-ssa/pta-escape-1.c: Likewise
	* gcc.dg/tree-ssa/pta-escape-2.c: Likewise
	* gcc.dg/tree-ssa/pta-escape-3.c: Likewise
	* gcc.dg/tree-ssa/ssa-pre-21.c: Likewise

	2010-10-12  Richard Guenther  <rguenther@suse.de>

	* tree-ssa-structalias.c (get_constraint_for_1): Constants
	only point to nonlocal, not anything.


Index: gcc/testsuite/gcc.dg/torture/pr39074-2.c
===================================================================
*** gcc/testsuite/gcc.dg/torture/pr39074-2.c.orig	2010-10-13 13:31:31.000000000 +0200
--- gcc/testsuite/gcc.dg/torture/pr39074-2.c	2010-10-18 16:04:29.000000000 +0200
*************** int main()
*** 30,34 ****
    return 0;
  }
  
! /* { dg-final { scan-tree-dump "y.._., points-to non-local, points-to escaped, points-to vars: { i }" "alias" } } */
  /* { dg-final { cleanup-tree-dump "alias" } } */
--- 30,34 ----
    return 0;
  }
  
! /* { dg-final { scan-tree-dump "y.._., points-to vars: { i }" "alias" } } */
  /* { dg-final { cleanup-tree-dump "alias" } } */
Index: gcc/testsuite/gcc.dg/torture/pr45967.c
===================================================================
*** /dev/null	1970-01-01 00:00:00.000000000 +0000
--- gcc/testsuite/gcc.dg/torture/pr45967.c	2010-10-18 13:33:30.000000000 +0200
***************
*** 0 ****
--- 1,21 ----
+ /* { dg-do run } */
+ 
+ extern void abort (void);
+ void __attribute__((noinline,noclone))
+ foo (void *p_)
+ {
+   int *p;
+   int i;
+   for (i = 0; i < sizeof(int *); ++i)
+     ((char *)&p)[i] = ((char *)p_)[i];
+   *p = 1;
+ }
+ int main()
+ {
+   int i = 0;
+   int *p = &i;
+   foo (&p);
+   if (i != 1)
+     abort ();
+   return 0;
+ }
Index: gcc/testsuite/gcc.dg/torture/pta-escape-1.c
===================================================================
*** gcc/testsuite/gcc.dg/torture/pta-escape-1.c.orig	2010-05-06 10:51:58.000000000 +0200
--- gcc/testsuite/gcc.dg/torture/pta-escape-1.c	2010-10-18 16:07:15.000000000 +0200
*************** main()
*** 30,34 ****
    return 0;
  }
  
! /* { dg-final { scan-tree-dump "ESCAPED = { ESCAPED NONLOCAL i }" "alias" } } */
  /* { dg-final { cleanup-tree-dump "alias" } } */
--- 30,34 ----
    return 0;
  }
  
! /* { dg-final { scan-tree-dump "ESCAPED = {\[^\n\}\]* i \[^\n\}\]*}" "alias" } } */
  /* { dg-final { cleanup-tree-dump "alias" } } */
Index: gcc/testsuite/gcc.dg/torture/pta-ptrarith-1.c
===================================================================
*** gcc/testsuite/gcc.dg/torture/pta-ptrarith-1.c.orig	2008-07-07 17:46:49.000000000 +0200
--- gcc/testsuite/gcc.dg/torture/pta-ptrarith-1.c	2010-10-18 16:12:21.000000000 +0200
*************** int main()
*** 29,33 ****
    return 0;
  }
  
! /* { dg-final { scan-tree-dump "ESCAPED = { ESCAPED NONLOCAL f .* i }" "alias" } } */
  /* { dg-final { cleanup-tree-dump "alias" } } */
--- 29,33 ----
    return 0;
  }
  
! /* { dg-final { scan-tree-dump "ESCAPED = {\[^\n\}\]* i f \[^\n\}\]*}" "alias" } } */
  /* { dg-final { cleanup-tree-dump "alias" } } */
Index: gcc/testsuite/gcc.dg/tree-ssa/pta-callused.c
===================================================================
*** gcc/testsuite/gcc.dg/tree-ssa/pta-callused.c.orig	2010-10-13 13:31:31.000000000 +0200
--- gcc/testsuite/gcc.dg/tree-ssa/pta-callused.c	2010-10-18 15:21:31.000000000 +0200
*************** int bar (int b)
*** 22,27 ****
    return *foo (&q);
  }
  
! /* { dg-final { scan-tree-dump "CALLUSED = { f.* i q }" "alias" } } */
  /* { dg-final { cleanup-tree-dump "alias" } } */
  
--- 22,27 ----
    return *foo (&q);
  }
  
! /* { dg-final { scan-tree-dump "CALLUSED = { ESCAPED NONLOCAL f.* i q }" "alias" } } */
  /* { dg-final { cleanup-tree-dump "alias" } } */
  
Index: gcc/testsuite/gcc.dg/tree-ssa/pta-escape-1.c
===================================================================
*** gcc/testsuite/gcc.dg/tree-ssa/pta-escape-1.c.orig	2010-05-06 10:51:58.000000000 +0200
--- gcc/testsuite/gcc.dg/tree-ssa/pta-escape-1.c	2010-10-18 15:24:01.000000000 +0200
*************** int main()
*** 33,37 ****
    return 0;
  }
  
! /* { dg-final { scan-tree-dump "ESCAPED, points-to non-local, points-to vars: { x }" "alias" } } */
  /* { dg-final { cleanup-tree-dump "alias" } } */
--- 33,37 ----
    return 0;
  }
  
! /* { dg-final { scan-tree-dump "ESCAPED, points-to non-local, points-to NULL, points-to vars: { x }" "alias" } } */
  /* { dg-final { cleanup-tree-dump "alias" } } */
Index: gcc/testsuite/gcc.dg/tree-ssa/pta-escape-2.c
===================================================================
*** gcc/testsuite/gcc.dg/tree-ssa/pta-escape-2.c.orig	2010-05-06 10:51:58.000000000 +0200
--- gcc/testsuite/gcc.dg/tree-ssa/pta-escape-2.c	2010-10-18 15:24:33.000000000 +0200
*************** int main()
*** 34,38 ****
    return 0;
  }
  
! /* { dg-final { scan-tree-dump "ESCAPED, points-to non-local, points-to vars: { x }" "alias" } } */
  /* { dg-final { cleanup-tree-dump "alias" } } */
--- 34,38 ----
    return 0;
  }
  
! /* { dg-final { scan-tree-dump "ESCAPED, points-to non-local, points-to NULL, points-to vars: { x }" "alias" } } */
  /* { dg-final { cleanup-tree-dump "alias" } } */
Index: gcc/testsuite/gcc.dg/tree-ssa/pta-escape-3.c
===================================================================
*** gcc/testsuite/gcc.dg/tree-ssa/pta-escape-3.c.orig	2010-05-06 10:51:58.000000000 +0200
--- gcc/testsuite/gcc.dg/tree-ssa/pta-escape-3.c	2010-10-18 15:25:14.000000000 +0200
*************** int main()
*** 38,42 ****
    return 0;
  }
  
! /* { dg-final { scan-tree-dump "ESCAPED, points-to non-local, points-to vars: { x }" "alias" } } */
  /* { dg-final { cleanup-tree-dump "alias" } } */
--- 38,42 ----
    return 0;
  }
  
! /* { dg-final { scan-tree-dump "ESCAPED, points-to non-local, points-to NULL, points-to vars: { x }" "alias" } } */
  /* { dg-final { cleanup-tree-dump "alias" } } */
Index: gcc/testsuite/gcc.dg/tree-ssa/ssa-pre-21.c
===================================================================
*** gcc/testsuite/gcc.dg/tree-ssa/ssa-pre-21.c.orig	2008-10-13 10:57:54.000000000 +0200
--- gcc/testsuite/gcc.dg/tree-ssa/ssa-pre-21.c	2010-10-18 15:27:24.000000000 +0200
*************** NumSift (long *array, unsigned long k)
*** 11,15 ****
  
  /* There should be only two loads left.  */
  
! /* { dg-final { scan-tree-dump-times "= \\\*D" 2 "pre" } } */
  /* { dg-final { cleanup-tree-dump "pre" } } */
--- 11,15 ----
  
  /* There should be only two loads left.  */
  
! /* { dg-final { scan-tree-dump-times "= \\\*D\[^\n;\]*;" 2 "pre" } } */
  /* { dg-final { cleanup-tree-dump "pre" } } */
Index: gcc/testsuite/gcc.dg/torture/pr45967-2.c
===================================================================
*** gcc/testsuite/gcc.dg/torture/pr45967-2.c	(revision 0)
--- gcc/testsuite/gcc.dg/torture/pr45967-2.c	(revision 0)
***************
*** 0 ****
--- 1,24 ----
+ /* { dg-do run } */
+ 
+ extern void abort (void);
+ int b;
+ void
+ foo (void *p_, int *q)
+ {
+   int *p;
+   int i;
+   for (i = 0; i < sizeof(int *); ++i)
+     ((char *)&p)[i] = ((char *)p_)[i];
+   if (b)
+     p = q;
+   *p = 1;
+ }
+ int main()
+ {
+   int i = 0, j;
+   int *p = &i;
+   foo (&p, &j);
+   if (i != 1)
+     abort ();
+   return 0;
+ }
Index: gcc/testsuite/gcc.dg/torture/pr45967-3.c
===================================================================
*** gcc/testsuite/gcc.dg/torture/pr45967-3.c	(revision 0)
--- gcc/testsuite/gcc.dg/torture/pr45967-3.c	(revision 0)
***************
*** 0 ****
--- 1,21 ----
+ /* { dg-do run } */
+ 
+ extern void abort (void);
+ void
+ foo (void *p_)
+ {
+   int *p;
+   int i;
+   for (i = 0; i < sizeof(int *); ++i)
+     ((char *)&p)[i] = ((char *)p_)[i];
+   *p = 1;
+ }
+ int main()
+ {
+   int i = 0;
+   int *p = &i;
+   foo (&p);
+   if (i != 1)
+     abort ();
+   return 0;
+ }
Index: gcc/tree-ssa-structalias.c
===================================================================
*** gcc/tree-ssa-structalias.c	(revision 170613)
--- gcc/tree-ssa-structalias.c	(working copy)
*************** process_constraint (constraint_t t)
*** 2788,2820 ****
      }
  }
  
- /* Return true if T is a type that could contain pointers.  */
- 
- static bool
- type_could_have_pointers (tree type)
- {
-   if (POINTER_TYPE_P (type))
-     return true;
- 
-   if (TREE_CODE (type) == ARRAY_TYPE)
-     return type_could_have_pointers (TREE_TYPE (type));
- 
-   return AGGREGATE_TYPE_P (type);
- }
- 
- /* Return true if T is a variable of a type that could contain
-    pointers.  */
- 
- static bool
- could_have_pointers (tree t)
- {
-   return (((TREE_CODE (t) == VAR_DECL
- 	    || TREE_CODE (t) == PARM_DECL
- 	    || TREE_CODE (t) == RESULT_DECL)
- 	   && (TREE_PUBLIC (t) || DECL_EXTERNAL (t) || TREE_ADDRESSABLE (t)))
- 	  || type_could_have_pointers (TREE_TYPE (t)));
- }
- 
  /* Return the position, in bits, of FIELD_DECL from the beginning of its
     structure.  */
  
--- 2788,2793 ----
*************** bitpos_of_field (const tree fdecl)
*** 2826,2832 ****
        || !host_integerp (DECL_FIELD_BIT_OFFSET (fdecl), 0))
      return -1;
  
!   return (TREE_INT_CST_LOW (DECL_FIELD_OFFSET (fdecl)) * 8
  	  + TREE_INT_CST_LOW (DECL_FIELD_BIT_OFFSET (fdecl)));
  }
  
--- 2799,2805 ----
        || !host_integerp (DECL_FIELD_BIT_OFFSET (fdecl), 0))
      return -1;
  
!   return (TREE_INT_CST_LOW (DECL_FIELD_OFFSET (fdecl)) * BITS_PER_UNIT
  	  + TREE_INT_CST_LOW (DECL_FIELD_BIT_OFFSET (fdecl)));
  }
  
*************** get_constraint_for_1 (tree t, VEC (ce_s,
*** 3167,3180 ****
       in that case *NULL does not fail, so it _should_ alias *anything.
       It is not worth adding a new option or renaming the existing one,
       since this case is relatively obscure.  */
!   if (flag_delete_null_pointer_checks
!       && ((TREE_CODE (t) == INTEGER_CST
! 	   && integer_zerop (t))
! 	  /* The only valid CONSTRUCTORs in gimple with pointer typed
! 	     elements are zero-initializer.  */
! 	  || TREE_CODE (t) == CONSTRUCTOR))
      {
!       temp.var = nothing_id;
        temp.type = ADDRESSOF;
        temp.offset = 0;
        VEC_safe_push (ce_s, heap, *results, &temp);
--- 3140,3157 ----
       in that case *NULL does not fail, so it _should_ alias *anything.
       It is not worth adding a new option or renaming the existing one,
       since this case is relatively obscure.  */
!   if ((TREE_CODE (t) == INTEGER_CST
!        && integer_zerop (t))
!       /* The only valid CONSTRUCTORs in gimple with pointer typed
! 	 elements are zero-initializer.  But in IPA mode we also
! 	 process global initializers, so verify at least.  */
!       || (TREE_CODE (t) == CONSTRUCTOR
! 	  && CONSTRUCTOR_NELTS (t) == 0))
      {
!       if (flag_delete_null_pointer_checks)
! 	temp.var = nothing_id;
!       else
! 	temp.var = nonlocal_id;
        temp.type = ADDRESSOF;
        temp.offset = 0;
        VEC_safe_push (ce_s, heap, *results, &temp);
*************** get_constraint_for_1 (tree t, VEC (ce_s,
*** 3247,3252 ****
--- 3224,3238 ----
  	get_constraint_for_ssa_var (t, results, address_p);
  	return;
        }
+     case tcc_constant:
+       {
+ 	/* We cannot refer to automatic variables through constants.  */
+ 	temp.type = ADDRESSOF;
+ 	temp.var = nonlocal_id;
+ 	temp.offset = 0;
+ 	VEC_safe_push (ce_s, heap, *results, &temp);
+ 	return;
+       }
      default:;
      }
  
*************** handle_rhs_call (gimple stmt, VEC(ce_s,
*** 3502,3509 ****
  
        /* Find those pointers being passed, and make sure they end up
  	 pointing to anything.  */
!       if (could_have_pointers (arg))
! 	make_escape_constraint (arg);
      }
  
    /* The static chain escapes as well.  */
--- 3488,3494 ----
  
        /* Find those pointers being passed, and make sure they end up
  	 pointing to anything.  */
!       make_escape_constraint (arg);
      }
  
    /* The static chain escapes as well.  */
*************** handle_const_call (gimple stmt, VEC(ce_s
*** 3603,3619 ****
    for (k = 0; k < gimple_call_num_args (stmt); ++k)
      {
        tree arg = gimple_call_arg (stmt, k);
! 
!       if (could_have_pointers (arg))
! 	{
! 	  VEC(ce_s, heap) *argc = NULL;
! 	  unsigned i;
! 	  struct constraint_expr *argp;
! 	  get_constraint_for_rhs (arg, &argc);
! 	  for (i = 0; VEC_iterate (ce_s, argc, i, argp); ++i)
! 	    VEC_safe_push (ce_s, heap, *results, argp);
! 	  VEC_free(ce_s, heap, argc);
! 	}
      }
  
    /* May return addresses of globals.  */
--- 3588,3600 ----
    for (k = 0; k < gimple_call_num_args (stmt); ++k)
      {
        tree arg = gimple_call_arg (stmt, k);
!       VEC(ce_s, heap) *argc = NULL;
!       unsigned i;
!       struct constraint_expr *argp;
!       get_constraint_for_rhs (arg, &argc);
!       for (i = 0; VEC_iterate (ce_s, argc, i, argp); ++i)
! 	VEC_safe_push (ce_s, heap, *results, argp);
!       VEC_free(ce_s, heap, argc);
      }
  
    /* May return addresses of globals.  */
*************** handle_pure_call (gimple stmt, VEC(ce_s,
*** 3637,3648 ****
    for (i = 0; i < gimple_call_num_args (stmt); ++i)
      {
        tree arg = gimple_call_arg (stmt, i);
! 
!       if (could_have_pointers (arg))
! 	{
! 	  make_constraint_to (callused_id, arg);
! 	  need_callused = true;
! 	}
      }
  
    /* The static chain is used as well.  */
--- 3618,3625 ----
    for (i = 0; i < gimple_call_num_args (stmt); ++i)
      {
        tree arg = gimple_call_arg (stmt, i);
!       make_constraint_to (callused_id, arg);
!       need_callused = true;
      }
  
    /* The static chain is used as well.  */
*************** find_func_aliases (gimple origt)
*** 3682,3715 ****
    /* Now build constraints expressions.  */
    if (gimple_code (t) == GIMPLE_PHI)
      {
!       gcc_assert (!AGGREGATE_TYPE_P (TREE_TYPE (gimple_phi_result (t))));
  
!       /* Only care about pointers and structures containing
! 	 pointers.  */
!       if (could_have_pointers (gimple_phi_result (t)))
! 	{
! 	  size_t i;
! 	  unsigned int j;
! 
! 	  /* For a phi node, assign all the arguments to
! 	     the result.  */
! 	  get_constraint_for (gimple_phi_result (t), &lhsc);
! 	  for (i = 0; i < gimple_phi_num_args (t); i++)
! 	    {
! 	      tree strippedrhs = PHI_ARG_DEF (t, i);
  
! 	      STRIP_NOPS (strippedrhs);
! 	      get_constraint_for_rhs (gimple_phi_arg_def (t, i), &rhsc);
  
! 	      for (j = 0; VEC_iterate (ce_s, lhsc, j, c); j++)
  		{
! 		  struct constraint_expr *c2;
! 		  while (VEC_length (ce_s, rhsc) > 0)
! 		    {
! 		      c2 = VEC_last (ce_s, rhsc);
! 		      process_constraint (new_constraint (*c, *c2));
! 		      VEC_pop (ce_s, rhsc);
! 		    }
  		}
  	    }
  	}
--- 3659,3685 ----
    /* Now build constraints expressions.  */
    if (gimple_code (t) == GIMPLE_PHI)
      {
!       size_t i;
!       unsigned int j;
  
!       /* For a phi node, assign all the arguments to
! 	 the result.  */
!       get_constraint_for (gimple_phi_result (t), &lhsc);
!       for (i = 0; i < gimple_phi_num_args (t); i++)
! 	{
! 	  tree strippedrhs = PHI_ARG_DEF (t, i);
  
! 	  STRIP_NOPS (strippedrhs);
! 	  get_constraint_for_rhs (gimple_phi_arg_def (t, i), &rhsc);
  
! 	  for (j = 0; VEC_iterate (ce_s, lhsc, j, c); j++)
! 	    {
! 	      struct constraint_expr *c2;
! 	      while (VEC_length (ce_s, rhsc) > 0)
  		{
! 		  c2 = VEC_last (ce_s, rhsc);
! 		  process_constraint (new_constraint (*c, *c2));
! 		  VEC_pop (ce_s, rhsc);
  		}
  	    }
  	}
*************** find_func_aliases (gimple origt)
*** 3858,3873 ****
  	  else
  	    handle_rhs_call (t, &rhsc);
  	  if (gimple_call_lhs (t))
! 	    {
! 	      if (could_have_pointers (gimple_call_lhs (t)))
! 		handle_lhs_call (gimple_call_lhs (t), flags, rhsc, fndecl);
! 	      /* Similar to conversions a result that is not a pointer
! 	         is an escape point for any pointer the function might
! 		 return.  */
! 	      else if (flags & (ECF_CONST|ECF_PURE
! 				|ECF_NOVOPS|ECF_LOOPING_CONST_OR_PURE))
! 		make_constraints_to (escaped_id, rhsc);
! 	    }
  	  VEC_free (ce_s, heap, rhsc);
  	}
        else
--- 3828,3834 ----
  	  else
  	    handle_rhs_call (t, &rhsc);
  	  if (gimple_call_lhs (t))
! 	    handle_lhs_call (gimple_call_lhs (t), flags, rhsc, fndecl);
  	  VEC_free (ce_s, heap, rhsc);
  	}
        else
*************** find_func_aliases (gimple origt)
*** 3950,3957 ****
    /* Otherwise, just a regular assignment statement.  Only care about
       operations with pointer result, others are dealt with as escape
       points if they have pointer operands.  */
!   else if (is_gimple_assign (t)
! 	   && type_could_have_pointers (TREE_TYPE (gimple_assign_lhs (t))))
      {
        /* Otherwise, just a regular assignment statement.  */
        tree lhsop = gimple_assign_lhs (t);
--- 3911,3917 ----
    /* Otherwise, just a regular assignment statement.  Only care about
       operations with pointer result, others are dealt with as escape
       points if they have pointer operands.  */
!   else if (is_gimple_assign (t))
      {
        /* Otherwise, just a regular assignment statement.  */
        tree lhsop = gimple_assign_lhs (t);
*************** find_func_aliases (gimple origt)
*** 3961,3983 ****
  	do_structure_copy (lhsop, rhsop);
        else
  	{
! 	  struct constraint_expr temp;
  	  get_constraint_for (lhsop, &lhsc);
  
! 	  if (gimple_assign_rhs_code (t) == POINTER_PLUS_EXPR)
  	    get_constraint_for_ptr_offset (gimple_assign_rhs1 (t),
  					   gimple_assign_rhs2 (t), &rhsc);
! 	  else if ((CONVERT_EXPR_CODE_P (gimple_assign_rhs_code (t))
  		    && !(POINTER_TYPE_P (gimple_expr_type (t))
  			 && !POINTER_TYPE_P (TREE_TYPE (rhsop))))
  		   || gimple_assign_single_p (t))
  	    get_constraint_for_rhs (rhsop, &rhsc);
  	  else
  	    {
! 	      temp.type = ADDRESSOF;
! 	      temp.var = anything_id;
! 	      temp.offset = 0;
! 	      VEC_safe_push (ce_s, heap, rhsc, &temp);
  	    }
  	  process_all_all_constraints (lhsc, rhsc);
  	}
--- 3921,3965 ----
  	do_structure_copy (lhsop, rhsop);
        else
  	{
! 	  enum tree_code code = gimple_assign_rhs_code (t);
! 
  	  get_constraint_for (lhsop, &lhsc);
  
! 	  if (code == POINTER_PLUS_EXPR)
  	    get_constraint_for_ptr_offset (gimple_assign_rhs1 (t),
  					   gimple_assign_rhs2 (t), &rhsc);
! 	  else if (code == BIT_AND_EXPR
! 		   && TREE_CODE (gimple_assign_rhs2 (t)) == INTEGER_CST)
! 	    {
! 	      /* Aligning a pointer via a BIT_AND_EXPR is offsetting
! 		 the pointer.  Handle it by offsetting it by UNKNOWN.  */
! 	      get_constraint_for_ptr_offset (gimple_assign_rhs1 (t),
! 					     NULL_TREE, &rhsc);
! 	    }
! 	  else if ((CONVERT_EXPR_CODE_P (code)
  		    && !(POINTER_TYPE_P (gimple_expr_type (t))
  			 && !POINTER_TYPE_P (TREE_TYPE (rhsop))))
  		   || gimple_assign_single_p (t))
  	    get_constraint_for_rhs (rhsop, &rhsc);
+ 	  else if (truth_value_p (code))
+ 	    /* Truth value results are not pointer (parts).  Or at least
+ 	       very very unreasonable obfuscation of a part.  */
+ 	    ;
  	  else
  	    {
! 	      /* All other operations are merges.  */
! 	      VEC (ce_s, heap) *tmp = NULL;
! 	      struct constraint_expr *rhsp;
! 	      unsigned i, j;
! 	      get_constraint_for_rhs (gimple_assign_rhs1 (t), &rhsc);
! 	      for (i = 2; i < gimple_num_ops (t); ++i)
! 		{
! 		  get_constraint_for_rhs (gimple_op (t, i), &tmp);
! 		  for (j = 0; VEC_iterate (ce_s, tmp, j, rhsp); ++j)
! 		    VEC_safe_push (ce_s, heap, rhsc, rhsp);
! 		  VEC_truncate (ce_s, tmp, 0);
! 		}
! 	      VEC_free (ce_s, heap, tmp);
  	    }
  	  process_all_all_constraints (lhsc, rhsc);
  	}
*************** find_func_aliases (gimple origt)
*** 3996,4012 ****
  	make_constraint_from_restrict (get_vi_for_tree (lhsop),
  				       "CAST_RESTRICT");
      }
-   /* For conversions of pointers to non-pointers the pointer escapes.  */
-   else if (gimple_assign_cast_p (t)
- 	   && POINTER_TYPE_P (TREE_TYPE (gimple_assign_rhs1 (t)))
- 	   && !POINTER_TYPE_P (TREE_TYPE (gimple_assign_lhs (t))))
-     {
-       make_escape_constraint (gimple_assign_rhs1 (t));
-     }
    /* Handle escapes through return.  */
    else if (gimple_code (t) == GIMPLE_RETURN
! 	   && gimple_return_retval (t) != NULL_TREE
! 	   && could_have_pointers (gimple_return_retval (t)))
      {
        make_escape_constraint (gimple_return_retval (t));
      }
--- 3978,3986 ----
  	make_constraint_from_restrict (get_vi_for_tree (lhsop),
  				       "CAST_RESTRICT");
      }
    /* Handle escapes through return.  */
    else if (gimple_code (t) == GIMPLE_RETURN
! 	   && gimple_return_retval (t) != NULL_TREE)
      {
        make_escape_constraint (gimple_return_retval (t));
      }
*************** find_func_aliases (gimple origt)
*** 4037,4043 ****
  
  	  /* The asm may read global memory, so outputs may point to
  	     any global memory.  */
! 	  if (op && could_have_pointers (op))
  	    {
  	      VEC(ce_s, heap) *lhsc = NULL;
  	      struct constraint_expr rhsc, *lhsp;
--- 4011,4017 ----
  
  	  /* The asm may read global memory, so outputs may point to
  	     any global memory.  */
! 	  if (op)
  	    {
  	      VEC(ce_s, heap) *lhsc = NULL;
  	      struct constraint_expr rhsc, *lhsp;
*************** find_func_aliases (gimple origt)
*** 4067,4073 ****
  	  /* Strictly we'd only need the constraint to ESCAPED if
  	     the asm clobbers memory, otherwise using CALLUSED
  	     would be enough.  */
! 	  else if (op && could_have_pointers (op))
  	    make_escape_constraint (op);
  	}
      }
--- 4041,4047 ----
  	  /* Strictly we'd only need the constraint to ESCAPED if
  	     the asm clobbers memory, otherwise using CALLUSED
  	     would be enough.  */
! 	  else if (op)
  	    make_escape_constraint (op);
  	}
      }
*************** struct fieldoff
*** 4192,4197 ****
--- 4166,4173 ----
  
    unsigned has_unknown_size : 1;
  
+   unsigned must_have_pointers : 1;
+ 
    unsigned may_have_pointers : 1;
  
    unsigned only_restrict_pointers : 1;
*************** var_can_have_subvars (const_tree v)
*** 4256,4261 ****
--- 4232,4264 ----
    return false;
  }
  
+ /* Return true if T is a type that does contain pointers.  */
+ 
+ static bool
+ type_must_have_pointers (tree type)
+ {
+   if (POINTER_TYPE_P (type))
+     return true;
+ 
+   if (TREE_CODE (type) == ARRAY_TYPE)
+     return type_must_have_pointers (TREE_TYPE (type));
+ 
+   /* A function or method can have pointers as arguments, so track
+      those separately.  */
+   if (TREE_CODE (type) == FUNCTION_TYPE
+       || TREE_CODE (type) == METHOD_TYPE)
+     return true;
+ 
+   return false;
+ }
+ 
+ static bool
+ field_must_have_pointers (tree t)
+ {
+   return type_must_have_pointers (TREE_TYPE (t));
+ }
+ 
+ 
  /* Given a TYPE, and a vector of field offsets FIELDSTACK, push all
     the fields of TYPE onto fieldstack, recording their offsets along
     the way.
*************** var_can_have_subvars (const_tree v)
*** 4266,4272 ****
  
  static int
  push_fields_onto_fieldstack (tree type, VEC(fieldoff_s,heap) **fieldstack,
! 			     HOST_WIDE_INT offset, bool must_have_pointers_p)
  {
    tree field;
    int count = 0;
--- 4269,4275 ----
  
  static int
  push_fields_onto_fieldstack (tree type, VEC(fieldoff_s,heap) **fieldstack,
! 			     HOST_WIDE_INT offset)
  {
    tree field;
    int count = 0;
*************** push_fields_onto_fieldstack (tree type,
*** 4292,4299 ****
  	    || TREE_CODE (TREE_TYPE (field)) == UNION_TYPE)
  	  push = true;
  	else if (!(pushed = push_fields_onto_fieldstack
! 		   (TREE_TYPE (field), fieldstack, offset + foff,
! 		    must_have_pointers_p))
  		 && (DECL_SIZE (field)
  		     && !integer_zerop (DECL_SIZE (field))))
  	  /* Empty structures may have actual size, like in C++.  So
--- 4295,4301 ----
  	    || TREE_CODE (TREE_TYPE (field)) == UNION_TYPE)
  	  push = true;
  	else if (!(pushed = push_fields_onto_fieldstack
! 		   (TREE_TYPE (field), fieldstack, offset + foff))
  		 && (DECL_SIZE (field)
  		     && !integer_zerop (DECL_SIZE (field))))
  	  /* Empty structures may have actual size, like in C++.  So
*************** push_fields_onto_fieldstack (tree type,
*** 4305,4310 ****
--- 4307,4313 ----
  	  {
  	    fieldoff_s *pair = NULL;
  	    bool has_unknown_size = false;
+ 	    bool must_have_pointers_p;
  
  	    if (!VEC_empty (fieldoff_s, *fieldstack))
  	      pair = VEC_last (fieldoff_s, *fieldstack);
*************** push_fields_onto_fieldstack (tree type,
*** 4325,4339 ****
  	      has_unknown_size = true;
  
  	    /* If adjacent fields do not contain pointers merge them.  */
  	    if (pair
- 		&& !pair->may_have_pointers
- 		&& !pair->has_unknown_size
  		&& !has_unknown_size
- 		&& pair->offset + (HOST_WIDE_INT)pair->size == offset + foff
  		&& !must_have_pointers_p
! 		&& !could_have_pointers (field))
  	      {
- 		pair = VEC_last (fieldoff_s, *fieldstack);
  		pair->size += TREE_INT_CST_LOW (DECL_SIZE (field));
  	      }
  	    else
--- 4328,4341 ----
  	      has_unknown_size = true;
  
  	    /* If adjacent fields do not contain pointers merge them.  */
+ 	    must_have_pointers_p = field_must_have_pointers (field);
  	    if (pair
  		&& !has_unknown_size
  		&& !must_have_pointers_p
! 		&& !pair->must_have_pointers
! 		&& !pair->has_unknown_size
! 		&& pair->offset + (HOST_WIDE_INT)pair->size == offset + foff)
  	      {
  		pair->size += TREE_INT_CST_LOW (DECL_SIZE (field));
  	      }
  	    else
*************** push_fields_onto_fieldstack (tree type,
*** 4345,4352 ****
  		  pair->size = TREE_INT_CST_LOW (DECL_SIZE (field));
  		else
  		  pair->size = -1;
! 		pair->may_have_pointers
! 		  = must_have_pointers_p || could_have_pointers (field);
  		pair->only_restrict_pointers
  		  = (!has_unknown_size
  		     && POINTER_TYPE_P (TREE_TYPE (field))
--- 4347,4354 ----
  		  pair->size = TREE_INT_CST_LOW (DECL_SIZE (field));
  		else
  		  pair->size = -1;
! 		pair->must_have_pointers = must_have_pointers_p;
! 		pair->may_have_pointers = true;
  		pair->only_restrict_pointers
  		  = (!has_unknown_size
  		     && POINTER_TYPE_P (TREE_TYPE (field))
*************** create_variable_info_for (tree decl, con
*** 4512,4528 ****
    VEC (fieldoff_s,heap) *fieldstack = NULL;
  
    if (var_can_have_subvars (decl) && use_field_sensitive)
!     push_fields_onto_fieldstack (decl_type, &fieldstack, 0,
! 				 TREE_PUBLIC (decl)
! 				 || DECL_EXTERNAL (decl)
! 				 || TREE_ADDRESSABLE (decl));
  
    /* If the variable doesn't have subvars, we may end up needing to
       sort the field list and create fake variables for all the
       fields.  */
    vi = new_var_info (decl, name);
    vi->offset = 0;
!   vi->may_have_pointers = could_have_pointers (decl);
    if (!declsize
        || !host_integerp (declsize, 1))
      {
--- 4514,4527 ----
    VEC (fieldoff_s,heap) *fieldstack = NULL;
  
    if (var_can_have_subvars (decl) && use_field_sensitive)
!     push_fields_onto_fieldstack (decl_type, &fieldstack, 0);
  
    /* If the variable doesn't have subvars, we may end up needing to
       sort the field list and create fake variables for all the
       fields.  */
    vi = new_var_info (decl, name);
    vi->offset = 0;
!   vi->may_have_pointers = true;
    if (!declsize
        || !host_integerp (declsize, 1))
      {
*************** intra_create_variable_infos (void)
*** 4695,4703 ****
      {
        varinfo_t p;
  
-       if (!could_have_pointers (t))
- 	continue;
- 
        /* For restrict qualified pointers to objects passed by
           reference build a real representative for the pointed-to object.  */
        if (DECL_BY_REFERENCE (t)
--- 4694,4699 ----



More information about the Gcc-patches mailing list