This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH] Handle builtin functions with pointer args/returns in PTA and the alias oracle


This implements knowledge about builtin functions with pointer arguments
and return values in points-to analysis as well as in the alias-oracle.
The effect is that arguments to most string and math functions do not
escape and that we know what their return values point to.  We also
can restrict clobbering to the relevant arguments.

Bootstrapped and tested on x86_64-unknown-linux-gnu, I'll apply this
tomorrow to let people time to comment.

I chickened out on all the printf-style stuff due to the usual
problem of glibc allowing hooks here.  If I missed commonly used
functions other than these please tell me.

Thanks,
Richard.

2009-06-18  Richard Guenther  <rguenther@suse.de>

	* tree-ssa-alias.c (ptr_deref_may_alias_decl_p): Handle
	ADDR_EXPR pointers.
	(ptr_derefs_may_alias_p): Likewise.
	(ptr_deref_may_alias_ref_p_1): New function.
	(ptr_deref_may_alias_ref_p): Likewise.
	(ref_maybe_used_by_call_p_1): Handle builtins that are not
	covered by looking at the ESCAPED solution.
	(call_may_clobber_ref_p_1): Likewise.
	* tree-ssa-structalias.c (get_constraint_for_ptr_offset):
	Handle NULL_TREE offset.  Do not produce redundant constraints.
	(process_all_all_constraints): New helper function.
	(do_structure_copy): Use it.
	(handle_lhs_call): Likewise.
	(find_func_aliases): Handle some builtins with pointer arguments
	and/or return values explicitly.

	* gcc.c-torture/execute/20090618-1.c: New testcase.

Index: gcc/tree-ssa-alias.c
===================================================================
*** gcc/tree-ssa-alias.c	(revision 148652)
--- gcc/tree-ssa-alias.c	(working copy)
*************** ptr_deref_may_alias_decl_p (tree ptr, tr
*** 168,181 ****
  {
    struct ptr_info_def *pi;
  
!   /* ???  During SCCVN/PRE we can end up with *&x during valueizing
!      operands.  Likewise we can end up with dereferencing constant
!      pointers.  Just bail out in these cases for now.  */
!   if (TREE_CODE (ptr) == ADDR_EXPR
!       || TREE_CODE (ptr) == INTEGER_CST)
!     return true;
! 
!   gcc_assert (TREE_CODE (ptr) == SSA_NAME
  	      && (TREE_CODE (decl) == VAR_DECL
  		  || TREE_CODE (decl) == PARM_DECL
  		  || TREE_CODE (decl) == RESULT_DECL));
--- 168,176 ----
  {
    struct ptr_info_def *pi;
  
!   gcc_assert ((TREE_CODE (ptr) == SSA_NAME
! 	       || TREE_CODE (ptr) == ADDR_EXPR
! 	       || TREE_CODE (ptr) == INTEGER_CST)
  	      && (TREE_CODE (decl) == VAR_DECL
  		  || TREE_CODE (decl) == PARM_DECL
  		  || TREE_CODE (decl) == RESULT_DECL));
*************** ptr_deref_may_alias_decl_p (tree ptr, tr
*** 184,189 ****
--- 179,207 ----
    if (!may_be_aliased (decl))
      return false;
  
+   /* ADDR_EXPR pointers either just offset another pointer or directly
+      specify the pointed-to set.  */
+   if (TREE_CODE (ptr) == ADDR_EXPR)
+     {
+       tree base = get_base_address (TREE_OPERAND (ptr, 0));
+       if (base
+ 	  && INDIRECT_REF_P (base))
+ 	ptr = TREE_OPERAND (base, 0);
+       else if (base
+ 	       && SSA_VAR_P (base))
+ 	return operand_equal_p (base, decl, 0);
+       else if (base
+ 	       && CONSTANT_CLASS_P (base))
+ 	return false;
+       else
+ 	return true;
+     }
+ 
+   /* We can end up with dereferencing constant pointers.
+      Just bail out in this case.  */
+   if (TREE_CODE (ptr) == INTEGER_CST)
+     return true;
+ 
    /* If we do not have useful points-to information for this pointer
       we cannot disambiguate anything else.  */
    pi = SSA_NAME_PTR_INFO (ptr);
*************** ptr_derefs_may_alias_p (tree ptr1, tree
*** 202,219 ****
  {
    struct ptr_info_def *pi1, *pi2;
  
!   /* ???  During SCCVN/PRE we can end up with *&x during valueizing
!      operands.  Likewise we can end up with dereferencing constant
!      pointers.  Just bail out in these cases for now.  */
!   if (TREE_CODE (ptr1) == ADDR_EXPR
!       || TREE_CODE (ptr1) == INTEGER_CST
!       || TREE_CODE (ptr2) == ADDR_EXPR
        || TREE_CODE (ptr2) == INTEGER_CST)
      return true;
  
-   gcc_assert (TREE_CODE (ptr1) == SSA_NAME
- 	      && TREE_CODE (ptr2) == SSA_NAME);
- 
    /* We may end up with two empty points-to solutions for two same pointers.
       In this case we still want to say both pointers alias, so shortcut
       that here.  */
--- 220,265 ----
  {
    struct ptr_info_def *pi1, *pi2;
  
!   gcc_assert ((TREE_CODE (ptr1) == SSA_NAME
! 	       || TREE_CODE (ptr1) == ADDR_EXPR
! 	       || TREE_CODE (ptr1) == INTEGER_CST)
! 	      && (TREE_CODE (ptr2) == SSA_NAME
! 		  || TREE_CODE (ptr2) == ADDR_EXPR
! 		  || TREE_CODE (ptr2) == INTEGER_CST));
! 
!   /* ADDR_EXPR pointers either just offset another pointer or directly
!      specify the pointed-to set.  */
!   if (TREE_CODE (ptr1) == ADDR_EXPR)
!     {
!       tree base = get_base_address (TREE_OPERAND (ptr1, 0));
!       if (base
! 	  && INDIRECT_REF_P (base))
! 	ptr1 = TREE_OPERAND (base, 0);
!       else if (base
! 	       && SSA_VAR_P (base))
! 	return ptr_deref_may_alias_decl_p (ptr2, base);
!       else
! 	return true;
!     }
!   if (TREE_CODE (ptr2) == ADDR_EXPR)
!     {
!       tree base = get_base_address (TREE_OPERAND (ptr2, 0));
!       if (base
! 	  && INDIRECT_REF_P (base))
! 	ptr2 = TREE_OPERAND (base, 0);
!       else if (base
! 	       && SSA_VAR_P (base))
! 	return ptr_deref_may_alias_decl_p (ptr1, base);
!       else
! 	return true;
!     }
! 
!   /* We can end up with dereferencing constant pointers.
!      Just bail out in this case.  */
!   if (TREE_CODE (ptr1) == INTEGER_CST
        || TREE_CODE (ptr2) == INTEGER_CST)
      return true;
  
    /* We may end up with two empty points-to solutions for two same pointers.
       In this case we still want to say both pointers alias, so shortcut
       that here.  */
*************** ptr_derefs_may_alias_p (tree ptr1, tree
*** 232,237 ****
--- 278,308 ----
    return pt_solutions_intersect (&pi1->pt, &pi2->pt);
  }
  
+ /* Return true if dereferencing PTR may alias *REF.
+    The caller is responsible for applying TBAA to see if PTR
+    may access *REF at all.  */
+ 
+ static bool
+ ptr_deref_may_alias_ref_p_1 (tree ptr, ao_ref *ref)
+ {
+   tree base = ao_ref_base (ref);
+ 
+   if (INDIRECT_REF_P (base))
+     return ptr_derefs_may_alias_p (ptr, TREE_OPERAND (base, 0));
+   else if (SSA_VAR_P (base))
+     return ptr_deref_may_alias_decl_p (ptr, base);
+ 
+   return true;
+ }
+ 
+ static bool
+ ptr_deref_may_alias_ref_p (tree ptr, tree ref)
+ {
+   ao_ref r;
+   ao_ref_init (&r, ref);
+   return ptr_deref_may_alias_ref_p_1 (ptr, &r);
+ }
+ 
  
  /* Dump alias information on FILE.  */
  
*************** refs_output_dependent_p (tree store1, tr
*** 778,784 ****
  static bool
  ref_maybe_used_by_call_p_1 (gimple call, tree ref)
  {
!   tree base;
    unsigned i;
    int flags = gimple_call_flags (call);
  
--- 849,855 ----
  static bool
  ref_maybe_used_by_call_p_1 (gimple call, tree ref)
  {
!   tree base, callee;
    unsigned i;
    int flags = gimple_call_flags (call);
  
*************** ref_maybe_used_by_call_p_1 (gimple call,
*** 803,815 ****
        && !is_global_var (base))
      goto process_args;
  
    /* Check if base is a global static variable that is not read
       by the function.  */
    if (TREE_CODE (base) == VAR_DECL
        && TREE_STATIC (base)
        && !TREE_PUBLIC (base))
      {
-       tree callee = gimple_call_fndecl (call);
        bitmap not_read;
  
        if (callee != NULL_TREE
--- 874,948 ----
        && !is_global_var (base))
      goto process_args;
  
+   callee = gimple_call_fndecl (call);
+ 
+   /* Handle those builtin functions explicitly that do not act as
+      escape points.  See tree-ssa-structalias.c:find_func_aliases
+      for the list of builtins we might need to handle here.  */
+   if (callee != NULL_TREE
+       && DECL_BUILT_IN_CLASS (callee) == BUILT_IN_NORMAL)
+     switch (DECL_FUNCTION_CODE (callee))
+       {
+ 	/* All the following functions clobber memory pointed to by
+ 	   their first argument.  */
+ 	case BUILT_IN_STRCPY:
+ 	case BUILT_IN_STRNCPY:
+ 	case BUILT_IN_BCOPY:
+ 	case BUILT_IN_MEMCPY:
+ 	case BUILT_IN_MEMMOVE:
+ 	case BUILT_IN_MEMPCPY:
+ 	case BUILT_IN_STPCPY:
+ 	case BUILT_IN_STPNCPY:
+ 	case BUILT_IN_STRCAT:
+ 	case BUILT_IN_STRNCAT:
+ 	  {
+ 	    tree src = gimple_call_arg (call, 1);
+ 	    return ptr_deref_may_alias_ref_p (src, ref);
+ 	  }
+ 	case BUILT_IN_FREXP:
+ 	case BUILT_IN_FREXPF:
+ 	case BUILT_IN_FREXPL:
+ 	case BUILT_IN_GAMMA_R:
+ 	case BUILT_IN_GAMMAF_R:
+ 	case BUILT_IN_GAMMAL_R:
+ 	case BUILT_IN_LGAMMA_R:
+ 	case BUILT_IN_LGAMMAF_R:
+ 	case BUILT_IN_LGAMMAL_R:
+ 	case BUILT_IN_MODF:
+ 	case BUILT_IN_MODFF:
+ 	case BUILT_IN_MODFL:
+ 	  {
+ 	    tree out = gimple_call_arg (call, 1);
+ 	    return ptr_deref_may_alias_ref_p (out, ref);
+ 	  }
+ 	case BUILT_IN_REMQUO:
+ 	case BUILT_IN_REMQUOF:
+ 	case BUILT_IN_REMQUOL:
+ 	  {
+ 	    tree out = gimple_call_arg (call, 2);
+ 	    return ptr_deref_may_alias_ref_p (out, ref);
+ 	  }
+ 	case BUILT_IN_SINCOS:
+ 	case BUILT_IN_SINCOSF:
+ 	case BUILT_IN_SINCOSL:
+ 	  {
+ 	    tree sin = gimple_call_arg (call, 1);
+ 	    tree cos = gimple_call_arg (call, 2);
+ 	    /* ???  We can use offset-based disambiguation here and factor
+ 	       refs_may_alias_p a bit more.  */
+ 	    return (ptr_deref_may_alias_ref_p (sin, ref)
+ 		    || ptr_deref_may_alias_ref_p (cos, ref));
+ 	  }
+ 	default:
+ 	  /* Fallthru to general call handling.  */;
+       }
+ 
    /* Check if base is a global static variable that is not read
       by the function.  */
    if (TREE_CODE (base) == VAR_DECL
        && TREE_STATIC (base)
        && !TREE_PUBLIC (base))
      {
        bitmap not_read;
  
        if (callee != NULL_TREE
*************** static bool
*** 901,906 ****
--- 1034,1040 ----
  call_may_clobber_ref_p_1 (gimple call, ao_ref *ref)
  {
    tree base;
+   tree callee;
  
    /* If the call is pure or const it cannot clobber anything.  */
    if (gimple_call_flags (call)
*************** call_may_clobber_ref_p_1 (gimple call, a
*** 926,943 ****
  	  || !is_global_var (base)))
      return false;
  
    /* Check if base is a global static variable that is not written
       by the function.  */
!   if (TREE_CODE (base) == VAR_DECL
        && TREE_STATIC (base)
        && !TREE_PUBLIC (base))
      {
-       tree callee = gimple_call_fndecl (call);
        bitmap not_written;
  
!       if (callee != NULL_TREE
! 	  && (not_written
! 	        = ipa_reference_get_not_written_global (cgraph_node (callee)))
  	  && bitmap_bit_p (not_written, DECL_UID (base)))
  	return false;
      }
--- 1060,1114 ----
  	  || !is_global_var (base)))
      return false;
  
+   callee = gimple_call_fndecl (call);
+ 
+   /* Handle those builtin functions explicitly that do not act as
+      escape points.  See tree-ssa-structalias.c:find_func_aliases
+      for the list of builtins we might need to handle here.  */
+   if (callee != NULL_TREE
+       && DECL_BUILT_IN_CLASS (callee) == BUILT_IN_NORMAL)
+     switch (DECL_FUNCTION_CODE (callee))
+       {
+ 	/* All the following functions clobber memory pointed to by
+ 	   their first argument.  */
+ 	case BUILT_IN_STRCPY:
+ 	case BUILT_IN_STRNCPY:
+ 	case BUILT_IN_BCOPY:
+ 	case BUILT_IN_MEMCPY:
+ 	case BUILT_IN_MEMMOVE:
+ 	case BUILT_IN_MEMPCPY:
+ 	case BUILT_IN_STPCPY:
+ 	case BUILT_IN_STPNCPY:
+ 	case BUILT_IN_STRCAT:
+ 	case BUILT_IN_STRNCAT:
+ 	  {
+ 	    tree dest = gimple_call_arg (call, 0);
+ 	    return ptr_deref_may_alias_ref_p_1 (dest, ref);
+ 	  }
+ 	/* Freeing memory kills the pointed-to memory.  More importantly
+ 	   the call has to serve as a barrier for moving loads and stores
+ 	   across it.  Same is true for memset.  */
+ 	case BUILT_IN_FREE:
+ 	case BUILT_IN_MEMSET:
+ 	  {
+ 	    tree ptr = gimple_call_arg (call, 0);
+ 	    return ptr_deref_may_alias_ref_p_1 (ptr, ref);
+ 	  }
+ 	default:
+ 	  /* Fallthru to general call handling.  */;
+       }
+ 
    /* Check if base is a global static variable that is not written
       by the function.  */
!   if (callee != NULL_TREE
!       && TREE_CODE (base) == VAR_DECL
        && TREE_STATIC (base)
        && !TREE_PUBLIC (base))
      {
        bitmap not_written;
  
!       if ((not_written
! 	     = ipa_reference_get_not_written_global (cgraph_node (callee)))
  	  && bitmap_bit_p (not_written, DECL_UID (base)))
  	return false;
      }
Index: gcc/tree-ssa-structalias.c
===================================================================
*** gcc/tree-ssa-structalias.c	(revision 148652)
--- gcc/tree-ssa-structalias.c	(working copy)
*************** get_constraint_for_ptr_offset (tree ptr,
*** 2857,2863 ****
       in a HOST_WIDE_INT, we have to fall back to a conservative
       solution which includes all sub-fields of all pointed-to
       variables of ptr.  */
!   if (!host_integerp (offset, 0))
      rhsoffset = UNKNOWN_OFFSET;
    else
      {
--- 2857,2864 ----
       in a HOST_WIDE_INT, we have to fall back to a conservative
       solution which includes all sub-fields of all pointed-to
       variables of ptr.  */
!   if (offset == NULL_TREE
!       || !host_integerp (offset, 0))
      rhsoffset = UNKNOWN_OFFSET;
    else
      {
*************** get_constraint_for_ptr_offset (tree ptr,
*** 2896,2902 ****
  	      c2.var = temp->id;
  	      c2.type = ADDRESSOF;
  	      c2.offset = 0;
! 	      VEC_safe_push (ce_s, heap, *results, &c2);
  	      temp = temp->next;
  	    }
  	  while (temp);
--- 2897,2904 ----
  	      c2.var = temp->id;
  	      c2.type = ADDRESSOF;
  	      c2.offset = 0;
! 	      if (c2.var != c->var)
! 		VEC_safe_push (ce_s, heap, *results, &c2);
  	      temp = temp->next;
  	    }
  	  while (temp);
*************** get_constraint_for (tree t, VEC (ce_s, h
*** 3239,3244 ****
--- 3241,3277 ----
    get_constraint_for_1 (t, results, false);
  }
  
+ 
+ /* Efficiently generates constraints from all entries in *RHSC to all
+    entries in *LHSC.  */
+ 
+ static void
+ process_all_all_constraints (VEC (ce_s, heap) *lhsc, VEC (ce_s, heap) *rhsc)
+ {
+   struct constraint_expr *lhsp, *rhsp;
+   unsigned i, j;
+ 
+   if (VEC_length (ce_s, lhsc) <= 1
+       || VEC_length (ce_s, rhsc) <= 1)
+     {
+       for (i = 0; VEC_iterate (ce_s, lhsc, i, lhsp); ++i)
+ 	for (j = 0; VEC_iterate (ce_s, rhsc, j, rhsp); ++j)
+ 	  process_constraint (new_constraint (*lhsp, *rhsp));
+     }
+   else
+     {
+       struct constraint_expr tmp;
+       tree tmpvar = create_tmp_var_raw (ptr_type_node, "allallcopytmp");
+       tmp.var = get_vi_for_tree (tmpvar)->id;
+       tmp.type = SCALAR;
+       tmp.offset = 0;
+       for (i = 0; VEC_iterate (ce_s, rhsc, i, rhsp); ++i)
+ 	process_constraint (new_constraint (tmp, *rhsp));
+       for (i = 0; VEC_iterate (ce_s, lhsc, i, lhsp); ++i)
+ 	process_constraint (new_constraint (*lhsp, tmp));
+     }
+ }
+ 
  /* Handle aggregate copies by expanding into copies of the respective
     fields of the structures.  */
  
*************** do_structure_copy (tree lhsop, tree rhso
*** 3256,3273 ****
    if (lhsp->type == DEREF
        || (lhsp->type == ADDRESSOF && lhsp->var == anything_id)
        || rhsp->type == DEREF)
!     {
!       struct constraint_expr tmp;
!       tree tmpvar = create_tmp_var_raw (ptr_type_node,
! 					"structcopydereftmp");
!       tmp.var = get_vi_for_tree (tmpvar)->id;
!       tmp.type = SCALAR;
!       tmp.offset = 0;
!       for (j = 0; VEC_iterate (ce_s, rhsc, j, rhsp); ++j)
! 	process_constraint (new_constraint (tmp, *rhsp));
!       for (j = 0; VEC_iterate (ce_s, lhsc, j, lhsp); ++j)
! 	process_constraint (new_constraint (*lhsp, tmp));
!     }
    else if (lhsp->type == SCALAR
  	   && (rhsp->type == SCALAR
  	       || rhsp->type == ADDRESSOF))
--- 3289,3295 ----
    if (lhsp->type == DEREF
        || (lhsp->type == ADDRESSOF && lhsp->var == anything_id)
        || rhsp->type == DEREF)
!     process_all_all_constraints (lhsc, rhsc);
    else if (lhsp->type == SCALAR
  	   && (rhsp->type == SCALAR
  	       || rhsp->type == ADDRESSOF))
*************** handle_lhs_call (tree lhs, int flags, VE
*** 3426,3433 ****
      }
    else if (VEC_length (ce_s, rhsc) > 0)
      {
-       struct constraint_expr *lhsp, *rhsp;
-       unsigned int i, j;
        /* If the store is to a global decl make sure to
  	 add proper escape constraints.  */
        lhs = get_base_address (lhs);
--- 3448,3453 ----
*************** handle_lhs_call (tree lhs, int flags, VE
*** 3441,3449 ****
  	  tmpc.type = SCALAR;
  	  VEC_safe_push (ce_s, heap, lhsc, &tmpc);
  	}
!       for (i = 0; VEC_iterate (ce_s, lhsc, i, lhsp); ++i)
! 	for (j = 0; VEC_iterate (ce_s, rhsc, j, rhsp); ++j)
! 	  process_constraint (new_constraint (*lhsp, *rhsp));
      }
    VEC_free (ce_s, heap, lhsc);
  }
--- 3461,3467 ----
  	  tmpc.type = SCALAR;
  	  VEC_safe_push (ce_s, heap, lhsc, &tmpc);
  	}
!       process_all_all_constraints (lhsc, rhsc);
      }
    VEC_free (ce_s, heap, lhsc);
  }
*************** find_func_aliases (gimple origt)
*** 3608,3613 ****
--- 3626,3733 ----
       pointer passed by address.  */
    else if (is_gimple_call (t))
      {
+       tree fndecl;
+       if ((fndecl = gimple_call_fndecl (t)) != NULL_TREE
+ 	  && DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL)
+ 	/* ???  All builtins that are handled here need to be handled
+ 	   in the alias-oracle query functions explicitly!  */
+ 	switch (DECL_FUNCTION_CODE (fndecl))
+ 	  {
+ 	  /* All the following functions return a pointer to the same object
+ 	     as their first argument points to.  The functions do not add
+ 	     to the ESCAPED solution.  The functions make the first argument
+ 	     pointed to memory point to what the second argument pointed to
+ 	     memory points to.  */
+ 	  case BUILT_IN_STRCPY:
+ 	  case BUILT_IN_STRNCPY:
+ 	  case BUILT_IN_BCOPY:
+ 	  case BUILT_IN_MEMCPY:
+ 	  case BUILT_IN_MEMMOVE:
+ 	  case BUILT_IN_MEMPCPY:
+ 	  case BUILT_IN_STPCPY:
+ 	  case BUILT_IN_STPNCPY:
+ 	  case BUILT_IN_STRCAT:
+ 	  case BUILT_IN_STRNCAT:
+ 	    {
+ 	      tree res = gimple_call_lhs (t);
+ 	      tree dest = gimple_call_arg (t, 0);
+ 	      tree src = gimple_call_arg (t, 1);
+ 	      if (res != NULL_TREE)
+ 		{
+ 		  get_constraint_for (res, &lhsc);
+ 		  if (DECL_FUNCTION_CODE (fndecl) == BUILT_IN_MEMPCPY
+ 		      || DECL_FUNCTION_CODE (fndecl) == BUILT_IN_STPCPY
+ 		      || DECL_FUNCTION_CODE (fndecl) == BUILT_IN_STPNCPY)
+ 		    get_constraint_for_ptr_offset (dest, NULL_TREE, &rhsc);
+ 		  else
+ 		    get_constraint_for (dest, &rhsc);
+ 		  process_all_all_constraints (lhsc, rhsc);
+ 		  VEC_free (ce_s, heap, lhsc);
+ 		  VEC_free (ce_s, heap, rhsc);
+ 		}
+ 	      get_constraint_for_ptr_offset (dest, NULL_TREE, &lhsc);
+ 	      get_constraint_for_ptr_offset (src, NULL_TREE, &rhsc);
+ 	      do_deref (&lhsc);
+ 	      do_deref (&rhsc);
+ 	      process_all_all_constraints (lhsc, rhsc);
+ 	      VEC_free (ce_s, heap, lhsc);
+ 	      VEC_free (ce_s, heap, rhsc);
+ 	      return;
+ 	    }
+ 	  case BUILT_IN_MEMSET:
+ 	    {
+ 	      tree res = gimple_call_lhs (t);
+ 	      tree dest = gimple_call_arg (t, 0);
+ 	      unsigned i;
+ 	      ce_s *lhsp;
+ 	      struct constraint_expr ac;
+ 	      if (res != NULL_TREE)
+ 		{
+ 		  get_constraint_for (res, &lhsc);
+ 		  get_constraint_for (dest, &rhsc);
+ 		  process_all_all_constraints (lhsc, rhsc);
+ 		  VEC_free (ce_s, heap, lhsc);
+ 		  VEC_free (ce_s, heap, rhsc);
+ 		}
+ 	      get_constraint_for_ptr_offset (dest, NULL_TREE, &lhsc);
+ 	      do_deref (&lhsc);
+ 	      ac.type = SCALAR;
+ 	      ac.var = integer_id;
+ 	      ac.offset = 0;
+ 	      for (i = 0; VEC_iterate (ce_s, lhsc, i, lhsp); ++i)
+ 		process_constraint (new_constraint (*lhsp, ac));
+ 	      VEC_free (ce_s, heap, lhsc);
+ 	      return;
+ 	    }
+ 	  /* All the following functions do not return pointers, do not
+ 	     modify the points-to sets of memory reachable from their
+ 	     arguments and do not add to the ESCAPED solution.  */
+ 	  case BUILT_IN_SINCOS:
+ 	  case BUILT_IN_SINCOSF:
+ 	  case BUILT_IN_SINCOSL:
+ 	  case BUILT_IN_FREXP:
+ 	  case BUILT_IN_FREXPF:
+ 	  case BUILT_IN_FREXPL:
+ 	  case BUILT_IN_GAMMA_R:
+ 	  case BUILT_IN_GAMMAF_R:
+ 	  case BUILT_IN_GAMMAL_R:
+ 	  case BUILT_IN_LGAMMA_R:
+ 	  case BUILT_IN_LGAMMAF_R:
+ 	  case BUILT_IN_LGAMMAL_R:
+ 	  case BUILT_IN_MODF:
+ 	  case BUILT_IN_MODFF:
+ 	  case BUILT_IN_MODFL:
+ 	  case BUILT_IN_REMQUO:
+ 	  case BUILT_IN_REMQUOF:
+ 	  case BUILT_IN_REMQUOL:
+ 	  case BUILT_IN_FREE:
+ 	    return;
+ 	  /* printf-style functions may have hooks to set pointers to
+ 	     point to somewhere into the generated string.  Leave them
+ 	     for a later excercise...  */
+ 	  default:
+ 	    /* Fallthru to general call handling.  */;
+ 	  }
        if (!in_ipa_mode)
  	{
  	  VEC(ce_s, heap) *rhsc = NULL;
*************** find_func_aliases (gimple origt)
*** 3724,3730 ****
  	do_structure_copy (lhsop, rhsop);
        else
  	{
- 	  unsigned int j;
  	  struct constraint_expr temp;
  	  get_constraint_for (lhsop, &lhsc);
  
--- 3844,3849 ----
*************** find_func_aliases (gimple origt)
*** 3743,3756 ****
  	      temp.offset = 0;
  	      VEC_safe_push (ce_s, heap, rhsc, &temp);
  	    }
! 	  for (j = 0; VEC_iterate (ce_s, lhsc, j, c); j++)
! 	    {
! 	      struct constraint_expr *c2;
! 	      unsigned int k;
! 
! 	      for (k = 0; VEC_iterate (ce_s, rhsc, k, c2); k++)
! 		process_constraint (new_constraint (*c, *c2));
! 	    }
  	}
        /* If there is a store to a global variable the rhs escapes.  */
        if ((lhsop = get_base_address (lhsop)) != NULL_TREE
--- 3862,3868 ----
  	      temp.offset = 0;
  	      VEC_safe_push (ce_s, heap, rhsc, &temp);
  	    }
! 	  process_all_all_constraints (lhsc, rhsc);
  	}
        /* If there is a store to a global variable the rhs escapes.  */
        if ((lhsop = get_base_address (lhsop)) != NULL_TREE
Index: gcc/testsuite/gcc.c-torture/execute/20090618-1.c
===================================================================
*** gcc/testsuite/gcc.c-torture/execute/20090618-1.c	(revision 0)
--- gcc/testsuite/gcc.c-torture/execute/20090618-1.c	(revision 0)
***************
*** 0 ****
--- 1,21 ----
+ extern void abort (void);
+ 
+ struct X { int *p; int *q; };
+ 
+ int foo(void)
+ {
+   int i = 0, j = 1;
+   struct X x, y;
+   int **p;
+   y.p = &i;
+   x.q = &j;
+   p = __builtin_mempcpy (&x, &y, sizeof (int *));
+   return **p;
+ }
+ 
+ int main()
+ {
+   if (foo() != 1)
+     abort ();
+   return 0;
+ }


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]