diff mbox series

Export info about side effects of builtins out of tree-ssa-alias.c

Message ID 20200927221605.GD52458@kam.mff.cuni.cz
State New
Headers show
Series Export info about side effects of builtins out of tree-ssa-alias.c | expand

Commit Message

Jan Hubicka Sept. 27, 2020, 10:16 p.m. UTC
Hi,
ipa-reference, ipa-pure-const and ipa-modref could use the knowledge
about bulitins which is currently harwired into
ref_maybe_used_by_call_p_1, call_may_clobber_ref_p_1 and the PTA
computation.  This patch breaks out logic implemented in the first two
into a form of a simple descriptor that can be used by the IPA passes
(and other code).

I was considering an option of putting this into def file but I do not think
it is feasible without cluttering it quite a lot.

For ipa-modref I implemented dump informing about missing builtins. strlen,
sqrt and exp seems common offenders, but that can be handled incrementally
if the approach looks reasonable.
I would also look adding the description for PTA (perhaps with some
special cases remainig since it is more ad-hoc)

Bootstrapped/regtested x86_64-linux, OK?

gcc/ChangeLog:

2020-09-28  Jan Hubicka  <hubicka@ucw.cz>

	* tree-ssa-alias.c (ao_classify_builtin): New function commonizing
	logic from ...
	(ref_maybe_used_by_call_p_1): ... here.
	(call_may_clobber_ref_p_1): ... and here.
	* tree-ssa-alias.h (enum ao_function_flags): New enum.
	(struct ao_function_info): New structure.
	(ao_classify_builtin): Declare.

Comments

Richard Biener Sept. 28, 2020, 8:12 a.m. UTC | #1
On Mon, 28 Sep 2020, Jan Hubicka wrote:

> Hi,
> ipa-reference, ipa-pure-const and ipa-modref could use the knowledge
> about bulitins which is currently harwired into
> ref_maybe_used_by_call_p_1, call_may_clobber_ref_p_1 and the PTA
> computation.  This patch breaks out logic implemented in the first two
> into a form of a simple descriptor that can be used by the IPA passes
> (and other code).
> 
> I was considering an option of putting this into def file but I do not think
> it is feasible without cluttering it quite a lot.
> 
> For ipa-modref I implemented dump informing about missing builtins. strlen,
> sqrt and exp seems common offenders, but that can be handled incrementally
> if the approach looks reasonable.
> I would also look adding the description for PTA (perhaps with some
> special cases remainig since it is more ad-hoc)
> 
> Bootstrapped/regtested x86_64-linux, OK?

Hmm, this looks awfully similar to fn-spec handling done in
process_args via gimple_call_arg_flags ()?

> gcc/ChangeLog:
> 
> 2020-09-28  Jan Hubicka  <hubicka@ucw.cz>
> 
> 	* tree-ssa-alias.c (ao_classify_builtin): New function commonizing
> 	logic from ...
> 	(ref_maybe_used_by_call_p_1): ... here.
> 	(call_may_clobber_ref_p_1): ... and here.
> 	* tree-ssa-alias.h (enum ao_function_flags): New enum.
> 	(struct ao_function_info): New structure.
> 	(ao_classify_builtin): Declare.
> 
> diff --git a/gcc/tree-ssa-alias.h b/gcc/tree-ssa-alias.h
> index 1dd02c0ea62..eecb8da6dd7 100644
> --- a/gcc/tree-ssa-alias.h
> +++ b/gcc/tree-ssa-alias.h
> @@ -108,6 +108,33 @@ ao_ref::max_size_known_p () const
>    return known_size_p (max_size);
>  }
>  
> +/* Flags used in ao_function_info.  */
> +
> +enum ao_function_flags
> +{
> +  AO_FUNCTION_BARRIER = 1,
> +  AO_FUNCTION_ERRNO = 2,
> +};
> +
> +/* Describe side effects relevant for alias analysis of function call to
> +   DECL.  */
> +
> +struct ao_function_info
> +{
> +  int num_param_reads;  /* Number of parameters function reads from,
> +			   -1 if reads are unknown.  */
> +  struct ao_access_info
> +    {
> +      char param; 	/* Index of parameter read/written from.  */
> +      char size_param;	/* Index of parameter specifying size of the access,
> +			   -1 if unknown.  */
> +      char size;	/* Size of access if known, 0 if unknown.  */
> +    } reads[2];
> +  int num_param_writes;
> +  struct ao_access_info writes[2];
> +  enum ao_function_flags flags;
> +};
> +
>  /* In tree-ssa-alias.c  */
>  extern void ao_ref_init (ao_ref *, tree);
>  extern void ao_ref_init_from_ptr_and_size (ao_ref *, tree, tree);
> @@ -158,6 +185,7 @@ extern void debug (pt_solution *ptr);
>  extern void dump_points_to_info_for (FILE *, tree);
>  extern void debug_points_to_info_for (tree);
>  extern void dump_alias_stats (FILE *);
> +extern bool ao_classify_builtin (tree callee, ao_function_info *info);
>  
>  
>  /* In tree-ssa-structalias.c  */
> diff --git a/gcc/tree-ssa-alias.c b/gcc/tree-ssa-alias.c
> index fe390d4ffbe..c182e7bb39c 100644
> --- a/gcc/tree-ssa-alias.c
> +++ b/gcc/tree-ssa-alias.c
> @@ -2503,6 +2503,507 @@ modref_may_conflict (const gimple *stmt,
>    return false;
>  }
>  
> +/* If CALLEE has known side effects, fill in INFO and return true.
> +   See tree-ssa-structalias.c:find_func_aliases
> +   for the list of builtins we might need to handle here.  */
> +
> +bool
> +ao_classify_builtin (tree callee, ao_function_info *info)
> +{
> +  built_in_function code = DECL_FUNCTION_CODE (callee);
> +
> +  switch (code)
> +    {
> +      /* All the following functions read memory pointed to by
> +	 their second argument and write memory pointed to by first
> +	 argument.
> +	 strcat/strncat additionally reads memory pointed to by the first
> +	 argument.  */
> +      case BUILT_IN_STRCAT:
> +	{
> +	  const static struct ao_function_info ret_info
> +	       = {
> +		    2,				/* num_param_reads.  */
> +
> +		    /* Reads and write descriptors are triples containing:
> +		       - index of parameter read
> +		       - index of parameter specifying access size
> +			 (-1 if unknown)
> +		       - access size in bytes (0 if unkown).  */
> +
> +		    {{0, -1, 0}, {1, -1, 0}},	/* Param read.  */
> +		    1,				/* num_param_writes.  */
> +		    {{0, -1, 0}},		/* Param written.  */
> +		    (ao_function_flags)0,	/* flags.  */
> +		 };
> +	  *info = ret_info;
> +	  return true;
> +	}
> +      case BUILT_IN_STRNCAT:
> +	{
> +	  const static struct ao_function_info ret_info
> +	       = {
> +		    2,				/* num_param_reads.  */
> +		    {{0, -1, 0}, {1, 2, 0}},	/* Param read.  */
> +		    1,				/* num_param_writes.  */
> +		    {{0, -1, 0}},		/* Param written.  */
> +		    (ao_function_flags)0,	/* flags.  */
> +		 };
> +	  *info = ret_info;
> +	  return true;
> +	}
> +      case BUILT_IN_STRCPY:
> +      case BUILT_IN_STPCPY:
> +	{
> +	  const static struct ao_function_info ret_info
> +	       = {
> +		    1,				/* num_param_reads.  */
> +		    {{1, -1, 0}},		/* Param read.  */
> +		    1,				/* num_param_writes.  */
> +		    {{0, -1, 0}},		/* Param written.  */
> +		    (ao_function_flags)0,	/* flags.  */
> +		 };
> +	  *info = ret_info;
> +	  return true;
> +	}
> +      case BUILT_IN_STRNCPY:
> +      case BUILT_IN_MEMCPY:
> +      case BUILT_IN_MEMMOVE:
> +      case BUILT_IN_MEMPCPY:
> +      case BUILT_IN_STPNCPY:
> +      case BUILT_IN_TM_MEMCPY:
> +      case BUILT_IN_TM_MEMMOVE:
> +	{
> +	  const static struct ao_function_info ret_info
> +	       = {
> +		    1,				/* num_param_reads.  */
> +		    {{1, 2, 0}},		/* Param read.  */
> +		    1,				/* num_param_writes.  */
> +		    {{0, 2, 0}},		/* Param written.  */
> +		    (ao_function_flags)0,	/* flags.  */
> +		 };
> +	  *info = ret_info;
> +	  return true;
> +	}
> +      case BUILT_IN_STRCAT_CHK:
> +	{
> +	  const static struct ao_function_info ret_info
> +	       = {
> +		    2,				/* num_param_reads.  */
> +		    {{0, -1, 0}, {1, -1, 0}},	/* Param read.  */
> +		    1,				/* num_param_writes.  */
> +		    {{0, -1, 0}},		/* Param written.  */
> +		    (ao_function_flags)0,	/* flags.  */
> +		 };
> +	  *info = ret_info;
> +	  return true;
> +	}
> +      case BUILT_IN_STRNCAT_CHK:
> +	{
> +	  const static struct ao_function_info ret_info
> +	       = {
> +		    2,				/* num_param_reads.  */
> +		    {{0, -1, 0}, {1, 2, 0}},	/* Param read.  */
> +		    1,				/* num_param_writes.  */
> +		    {{0, -1, 0}},		/* Param written.  */
> +		    (ao_function_flags)0,	/* flags.  */
> +		 };
> +	  *info = ret_info;
> +	  return true;
> +	}
> +      case BUILT_IN_STRCPY_CHK:
> +      case BUILT_IN_STPCPY_CHK:
> +	{
> +	  const static struct ao_function_info ret_info
> +	       = {
> +		    1,				/* num_param_reads.  */
> +		    {{1, -1, 0}},		/* Param read.  */
> +		    1,				/* num_param_writes.  */
> +		    {{0, -1, 0}},		/* Param written.  */
> +		    (ao_function_flags)0,	/* flags.  */
> +		 };
> +	  *info = ret_info;
> +	  return true;
> +	}
> +      case BUILT_IN_STRNCPY_CHK:
> +      case BUILT_IN_MEMCPY_CHK:
> +      case BUILT_IN_MEMMOVE_CHK:
> +      case BUILT_IN_MEMPCPY_CHK:
> +      case BUILT_IN_STPNCPY_CHK:
> +	{
> +	  const static struct ao_function_info ret_info
> +	       = {
> +		    1,				/* num_param_reads.  */
> +		    {{1, 2, 0}},		/* Param read.  */
> +		    1,				/* num_param_writes.  */
> +		    {{0, 2, 0}},		/* Param written.  */
> +		    (ao_function_flags)0,	/* flags.  */
> +		 };
> +	  *info = ret_info;
> +	  return true;
> +	}
> +      case BUILT_IN_BCOPY:
> +	{
> +	  const static struct ao_function_info ret_info
> +	       = {
> +		    1,				/* num_param_reads.  */
> +		    {{0, 2, 0}},		/* Param read.  */
> +		    1,				/* num_param_writes.  */
> +		    {{1, 2, 0}},		/* Param written.  */
> +		    (ao_function_flags)0,	/* flags.  */
> +		 };
> +	  *info = ret_info;
> +	  return true;
> +	}
> +
> +      /* The following functions read memory pointed to by their
> +	 first argument.  */
> +      CASE_BUILT_IN_TM_LOAD (1):
> +      CASE_BUILT_IN_TM_LOAD (2):
> +      CASE_BUILT_IN_TM_LOAD (4):
> +      CASE_BUILT_IN_TM_LOAD (8):
> +      CASE_BUILT_IN_TM_LOAD (FLOAT):
> +      CASE_BUILT_IN_TM_LOAD (DOUBLE):
> +      CASE_BUILT_IN_TM_LOAD (LDOUBLE):
> +      CASE_BUILT_IN_TM_LOAD (M64):
> +      CASE_BUILT_IN_TM_LOAD (M128):
> +      CASE_BUILT_IN_TM_LOAD (M256):
> +      case BUILT_IN_TM_LOG:
> +      case BUILT_IN_TM_LOG_1:
> +      case BUILT_IN_TM_LOG_2:
> +      case BUILT_IN_TM_LOG_4:
> +      case BUILT_IN_TM_LOG_8:
> +      case BUILT_IN_TM_LOG_FLOAT:
> +      case BUILT_IN_TM_LOG_DOUBLE:
> +      case BUILT_IN_TM_LOG_LDOUBLE:
> +      case BUILT_IN_TM_LOG_M64:
> +      case BUILT_IN_TM_LOG_M128:
> +      case BUILT_IN_TM_LOG_M256:
> +
> +      case BUILT_IN_INDEX:
> +      case BUILT_IN_STRCHR:
> +      case BUILT_IN_STRRCHR:
> +	{
> +	  const static struct ao_function_info ret_info
> +	       = {
> +		    1,				/* num_param_reads.  */
> +		    /* TODO: For TM builtins size is known.  */
> +		    {{0, -1, 0}},		/* Param read.  */
> +		    0,				/* num_param_writes.  */
> +		    {},				/* Param written.  */
> +		    (ao_function_flags)0,	/* flags.  */
> +		 };
> +	  *info = ret_info;
> +	  return true;
> +	}
> +
> +      /* These read memory pointed to by the first argument.
> +	 Allocating memory does not have any side-effects apart from
> +	 being the definition point for the pointer.
> +	 Unix98 specifies that errno is set on allocation failure.  */
> +      case BUILT_IN_STRDUP:
> +	{
> +	  const static struct ao_function_info ret_info
> +	       = {
> +		    1,				/* num_param_reads.  */
> +		    {{0, -1, 0}},		/* Param read.  */
> +		    0,				/* num_param_writes.  */
> +		    {},				/* Param written.  */
> +		    AO_FUNCTION_ERRNO,		/* flags.  */
> +		 };
> +	  *info = ret_info;
> +	  return true;
> +	}
> +      case BUILT_IN_STRNDUP:
> +	{
> +	  const static struct ao_function_info ret_info
> +	       = {
> +		    1,				/* num_param_reads.  */
> +		    {{0, 1, 0}},		/* Param read.  */
> +		    0,				/* num_param_writes.  */
> +		    {},				/* Param written.  */
> +		    AO_FUNCTION_ERRNO,		/* flags.  */
> +		 };
> +	  *info = ret_info;
> +	  return true;
> +	}
> +      /* Allocating memory does not have any side-effects apart from
> +	 being the definition point for the pointer.  */
> +      case BUILT_IN_MALLOC:
> +      case BUILT_IN_ALIGNED_ALLOC:
> +      case BUILT_IN_CALLOC:
> +	{
> +	  const static struct ao_function_info ret_info
> +	       = {
> +		    0,				/* num_param_reads.  */
> +		    {},				/* Param read.  */
> +		    0,				/* num_param_writes.  */
> +		    {},				/* Param written.  */
> +		    AO_FUNCTION_ERRNO,		/* flags.  */
> +		 };
> +	  *info = ret_info;
> +	  return true;
> +	}
> +      /* These read memory pointed to by the first argument with size
> +	 in the third argument.  */
> +      case BUILT_IN_MEMCHR:
> +	{
> +	  const static struct ao_function_info ret_info
> +	       = {
> +		    1,				/* num_param_reads.  */
> +		    {{0, 2, 0}},		/* Param read.  */
> +		    0,				/* num_param_writes.  */
> +		    {},				/* Param written.  */
> +		    (ao_function_flags)0,	/* flags.  */
> +		 };
> +	  *info = ret_info;
> +	  return true;
> +	}
> +      /* These read memory pointed to by the first and second arguments.  */
> +      case BUILT_IN_STRSTR:
> +      case BUILT_IN_STRPBRK:
> +	{
> +	  static struct ao_function_info ret_info
> +	       = {
> +		    2,				/* num_param_reads.  */
> +		    {{0, -1, 0}, {1, -1, 0}},	/* Param read.  */
> +		    0,				/* num_param_writes.  */
> +		    {},				/* Param written.  */
> +		    (ao_function_flags)0,	/* flags.  */
> +		 };
> +	  *info = ret_info;
> +	  return true;
> +	}
> +      /* Freeing memory kills the pointed-to memory.  More importantly
> +	 the call has to serve as a barrier for moving loads and stores
> +	 across it.  */
> +      case BUILT_IN_FREE:
> +      case BUILT_IN_VA_END:
> +	{
> +	  const static struct ao_function_info ret_info
> +	       = {
> +		    0,				/* num_param_reads.  */
> +		    {},				/* Param read.  */
> +		    1,				/* num_param_writes.  */
> +		    {{0, -1, 0}},		/* Param written.  */
> +		    (ao_function_flags)0,	/* flags.  */
> +		 };
> +	  *info = ret_info;
> +	  return true;
> +	}
> +      /* Realloc serves both as allocation point and deallocation point.  */
> +      case BUILT_IN_REALLOC:
> +	{
> +	  const static struct ao_function_info ret_info
> +	       = {
> +		    1,				/* num_param_reads.  */
> +		    {{0, 1, 0}},		/* Param read.  */
> +		    0,				/* num_param_writes.  */
> +		    {{0, -1, 0}},		/* Param written.  */
> +		    AO_FUNCTION_ERRNO,		/* flags.  */
> +		 };
> +	  *info = ret_info;
> +	  return true;
> +	}
> +      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:
> +	{
> +	  const static struct ao_function_info ret_info
> +	       = {
> +		    0,				/* num_param_reads.  */
> +		    {},				/* Param read.  */
> +		    1,				/* num_param_writes.  */
> +		    {{1, -1, 0}},		/* Param written.  */
> +		    AO_FUNCTION_ERRNO,		/* flags.  */
> +		 };
> +	  *info = ret_info;
> +	  return true;
> +	}
> +      case BUILT_IN_FREXP:
> +      case BUILT_IN_FREXPF:
> +      case BUILT_IN_FREXPL:
> +      case BUILT_IN_MODF:
> +      case BUILT_IN_MODFF:
> +      case BUILT_IN_MODFL:
> +	{
> +	  const static struct ao_function_info ret_info
> +	       = {
> +		    0,				/* num_param_reads.  */
> +		    {},				/* Param read.  */
> +		    1,				/* num_param_writes.  */
> +		    {{1, -1, 0}},		/* Param written.  */
> +		    (ao_function_flags)0,	/* flags.  */
> +		 };
> +	  *info = ret_info;
> +	  return true;
> +	}
> +      case BUILT_IN_REMQUO:
> +      case BUILT_IN_REMQUOF:
> +      case BUILT_IN_REMQUOL:
> +	{
> +	  const static struct ao_function_info ret_info
> +	       = {
> +		    0,				/* num_param_reads.  */
> +		    {},				/* Param read.  */
> +		    1,				/* num_param_writes.  */
> +		    {{2, -1, 0}},		/* Param written.  */
> +		    (ao_function_flags)0,	/* flags.  */
> +		 };
> +	  *info = ret_info;
> +	  return true;
> +	}
> +      case BUILT_IN_SINCOS:
> +      case BUILT_IN_SINCOSF:
> +      case BUILT_IN_SINCOSL:
> +	{
> +	  static struct ao_function_info ret_info
> +	       = {
> +		    0,				/* num_param_reads.  */
> +		    {},				/* Param read.  */
> +		    1,				/* num_param_writes.  */
> +		    {{1, -1, 0}, {2, -1, 0}},	/* Param written.  */
> +		    (ao_function_flags)0,	/* flags.  */
> +		 };
> +	  tree type = float_ptr_type_node;
> +	  if (code == BUILT_IN_SINCOS)
> +	    type = double_ptr_type_node;
> +	  else
> +	    type = long_double_ptr_type_node;
> +	  ret_info.writes[0].size = ret_info.writes[1].size
> +		 = tree_to_uhwi (TYPE_SIZE_UNIT (type));
> +	  *info = ret_info;
> +	  return true;
> +	}
> +      case BUILT_IN_MEMSET:
> +      case BUILT_IN_MEMSET_CHK:
> +      case BUILT_IN_TM_MEMSET:
> +	{
> +	  const static struct ao_function_info ret_info
> +	       = {
> +		    0,				/* num_param_reads.  */
> +		    {},				/* Param read.  */
> +		    1,				/* num_param_writes.  */
> +		    {0, 2, 0},			/* Param written.  */
> +		    (ao_function_flags)0,	/* flags.  */
> +		 };
> +	  *info = ret_info;
> +	  return true;
> +	}
> +      CASE_BUILT_IN_TM_STORE (1):
> +      CASE_BUILT_IN_TM_STORE (2):
> +      CASE_BUILT_IN_TM_STORE (4):
> +      CASE_BUILT_IN_TM_STORE (8):
> +      CASE_BUILT_IN_TM_STORE (FLOAT):
> +      CASE_BUILT_IN_TM_STORE (DOUBLE):
> +      CASE_BUILT_IN_TM_STORE (LDOUBLE):
> +      CASE_BUILT_IN_TM_STORE (M64):
> +      CASE_BUILT_IN_TM_STORE (M128):
> +      CASE_BUILT_IN_TM_STORE (M256):
> +	{
> +	  const static struct ao_function_info ret_info
> +	       = {
> +		    0,				/* num_param_reads.  */
> +		    {},				/* Param read.  */
> +		    1,				/* num_param_writes.  */
> +		    /* TODO: Size is known.  */
> +		    {0, -1, 0},			/* Param written.  */
> +		    (ao_function_flags)0,	/* flags.  */
> +		 };
> +	  *info = ret_info;
> +	  return true;
> +	}
> +      case BUILT_IN_STACK_SAVE:
> +      CASE_BUILT_IN_ALLOCA:
> +      case BUILT_IN_ASSUME_ALIGNED:
> +	{
> +	  const static struct ao_function_info ret_info
> +	       = {
> +		    0,				/* num_param_reads.  */
> +		    {},				/* Param read.  */
> +		    0,				/* num_param_writes.  */
> +		    {},				/* Param written.  */
> +		    (ao_function_flags)0,	/* flags.  */
> +		 };
> +	  *info = ret_info;
> +	  return true;
> +	}
> +      /* But posix_memalign stores a pointer into the memory pointed to
> +	 by its first argument.  */
> +      case BUILT_IN_POSIX_MEMALIGN:
> +	{
> +	  static struct ao_function_info ret_info
> +	       = {
> +		    0,				/* num_param_reads.  */
> +		    {},				/* Param read.  */
> +		    0,				/* num_param_writes.  */
> +		    {{0, -1, 0}},		/* Param written.  */
> +		    AO_FUNCTION_ERRNO,		/* flags.  */
> +		 };
> +	  ret_info.writes[0].size
> +		 = tree_to_uhwi (TYPE_SIZE_UNIT (ptr_type_node));
> +	  *info = ret_info;
> +	  return true;
> +	}
> +      /* The following builtins do not read from memory.  */
> +      case BUILT_IN_STACK_RESTORE:
> +	{
> +	  const static struct ao_function_info ret_info
> +	       = {
> +		    0,				/* num_param_reads.  */
> +		    {},				/* Param read.  */
> +		    0,				/* num_param_writes.  */
> +		    {},				/* Param written.  */
> +		    (ao_function_flags)0,	/* flags.  */
> +		 };
> +	  *info = ret_info;
> +	  return true;
> +	}
> +      /* __sync_* builtins and some OpenMP builtins act as threading
> +	 barriers.  */
> +#undef DEF_SYNC_BUILTIN
> +#define DEF_SYNC_BUILTIN(ENUM, NAME, TYPE, ATTRS) case ENUM:
> +#include "sync-builtins.def"
> +#undef DEF_SYNC_BUILTIN
> +      case BUILT_IN_GOMP_ATOMIC_START:
> +      case BUILT_IN_GOMP_ATOMIC_END:
> +      case BUILT_IN_GOMP_BARRIER:
> +      case BUILT_IN_GOMP_BARRIER_CANCEL:
> +      case BUILT_IN_GOMP_TASKWAIT:
> +      case BUILT_IN_GOMP_TASKGROUP_END:
> +      case BUILT_IN_GOMP_CRITICAL_START:
> +      case BUILT_IN_GOMP_CRITICAL_END:
> +      case BUILT_IN_GOMP_CRITICAL_NAME_START:
> +      case BUILT_IN_GOMP_CRITICAL_NAME_END:
> +      case BUILT_IN_GOMP_LOOP_END:
> +      case BUILT_IN_GOMP_LOOP_END_CANCEL:
> +      case BUILT_IN_GOMP_ORDERED_START:
> +      case BUILT_IN_GOMP_ORDERED_END:
> +      case BUILT_IN_GOMP_SECTIONS_END:
> +      case BUILT_IN_GOMP_SECTIONS_END_CANCEL:
> +      case BUILT_IN_GOMP_SINGLE_COPY_START:
> +      case BUILT_IN_GOMP_SINGLE_COPY_END:
> +	{
> +	  const static struct ao_function_info ret_info
> +	       = {
> +		    -1,				/* num_param_reads.  */
> +		    {},				/* Param read.  */
> +		    -1,				/* num_param_writes.  */
> +		    {},				/* Param written.  */
> +		    AO_FUNCTION_BARRIER,	/* flags.  */
> +		 };
> +	  *info = ret_info;
> +	  return true;
> +	}
> +
> +      default:
> +	return false;
> +    }
> +}
> +
>  /* If the call CALL may use the memory reference REF return true,
>     otherwise return false.  */
>  
> @@ -2574,219 +3075,37 @@ ref_maybe_used_by_call_p_1 (gcall *call, ao_ref *ref, bool tbaa_p)
>    /* 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.  */
> +  struct ao_function_info info;
>    if (callee != NULL_TREE
> -      && gimple_call_builtin_p (call, BUILT_IN_NORMAL))
> -    switch (DECL_FUNCTION_CODE (callee))
> -      {
> -	/* All the following functions read memory pointed to by
> -	   their second argument.  strcat/strncat additionally
> -	   reads memory pointed to by the first argument.  */
> -	case BUILT_IN_STRCAT:
> -	case BUILT_IN_STRNCAT:
> -	  {
> -	    ao_ref dref;
> -	    ao_ref_init_from_ptr_and_size (&dref,
> -					   gimple_call_arg (call, 0),
> -					   NULL_TREE);
> -	    if (refs_may_alias_p_1 (&dref, ref, false))
> -	      return true;
> -	  }
> -	  /* FALLTHRU */
> -	case BUILT_IN_STRCPY:
> -	case BUILT_IN_STRNCPY:
> -	case BUILT_IN_MEMCPY:
> -	case BUILT_IN_MEMMOVE:
> -	case BUILT_IN_MEMPCPY:
> -	case BUILT_IN_STPCPY:
> -	case BUILT_IN_STPNCPY:
> -	case BUILT_IN_TM_MEMCPY:
> -	case BUILT_IN_TM_MEMMOVE:
> -	  {
> -	    ao_ref dref;
> -	    tree size = NULL_TREE;
> -	    if (gimple_call_num_args (call) == 3)
> -	      size = gimple_call_arg (call, 2);
> -	    ao_ref_init_from_ptr_and_size (&dref,
> -					   gimple_call_arg (call, 1),
> -					   size);
> -	    return refs_may_alias_p_1 (&dref, ref, false);
> -	  }
> -	case BUILT_IN_STRCAT_CHK:
> -	case BUILT_IN_STRNCAT_CHK:
> -	  {
> -	    ao_ref dref;
> -	    ao_ref_init_from_ptr_and_size (&dref,
> -					   gimple_call_arg (call, 0),
> -					   NULL_TREE);
> -	    if (refs_may_alias_p_1 (&dref, ref, false))
> -	      return true;
> -	  }
> -	  /* FALLTHRU */
> -	case BUILT_IN_STRCPY_CHK:
> -	case BUILT_IN_STRNCPY_CHK:
> -	case BUILT_IN_MEMCPY_CHK:
> -	case BUILT_IN_MEMMOVE_CHK:
> -	case BUILT_IN_MEMPCPY_CHK:
> -	case BUILT_IN_STPCPY_CHK:
> -	case BUILT_IN_STPNCPY_CHK:
> -	  {
> -	    ao_ref dref;
> -	    tree size = NULL_TREE;
> -	    if (gimple_call_num_args (call) == 4)
> -	      size = gimple_call_arg (call, 2);
> -	    ao_ref_init_from_ptr_and_size (&dref,
> -					   gimple_call_arg (call, 1),
> -					   size);
> -	    return refs_may_alias_p_1 (&dref, ref, false);
> -	  }
> -	case BUILT_IN_BCOPY:
> -	  {
> -	    ao_ref dref;
> -	    tree size = gimple_call_arg (call, 2);
> -	    ao_ref_init_from_ptr_and_size (&dref,
> -					   gimple_call_arg (call, 0),
> -					   size);
> -	    return refs_may_alias_p_1 (&dref, ref, false);
> -	  }
> -
> -	/* The following functions read memory pointed to by their
> -	   first argument.  */
> -	CASE_BUILT_IN_TM_LOAD (1):
> -	CASE_BUILT_IN_TM_LOAD (2):
> -	CASE_BUILT_IN_TM_LOAD (4):
> -	CASE_BUILT_IN_TM_LOAD (8):
> -	CASE_BUILT_IN_TM_LOAD (FLOAT):
> -	CASE_BUILT_IN_TM_LOAD (DOUBLE):
> -	CASE_BUILT_IN_TM_LOAD (LDOUBLE):
> -	CASE_BUILT_IN_TM_LOAD (M64):
> -	CASE_BUILT_IN_TM_LOAD (M128):
> -	CASE_BUILT_IN_TM_LOAD (M256):
> -	case BUILT_IN_TM_LOG:
> -	case BUILT_IN_TM_LOG_1:
> -	case BUILT_IN_TM_LOG_2:
> -	case BUILT_IN_TM_LOG_4:
> -	case BUILT_IN_TM_LOG_8:
> -	case BUILT_IN_TM_LOG_FLOAT:
> -	case BUILT_IN_TM_LOG_DOUBLE:
> -	case BUILT_IN_TM_LOG_LDOUBLE:
> -	case BUILT_IN_TM_LOG_M64:
> -	case BUILT_IN_TM_LOG_M128:
> -	case BUILT_IN_TM_LOG_M256:
> -	  return ptr_deref_may_alias_ref_p_1 (gimple_call_arg (call, 0), ref);
> -
> -	/* These read memory pointed to by the first argument.  */
> -	case BUILT_IN_STRDUP:
> -	case BUILT_IN_STRNDUP:
> -	case BUILT_IN_REALLOC:
> -	  {
> -	    ao_ref dref;
> -	    tree size = NULL_TREE;
> -	    if (gimple_call_num_args (call) == 2)
> -	      size = gimple_call_arg (call, 1);
> -	    ao_ref_init_from_ptr_and_size (&dref,
> -					   gimple_call_arg (call, 0),
> -					   size);
> -	    return refs_may_alias_p_1 (&dref, ref, false);
> -	  }
> -	/* These read memory pointed to by the first argument.  */
> -	case BUILT_IN_INDEX:
> -	case BUILT_IN_STRCHR:
> -	case BUILT_IN_STRRCHR:
> -	  {
> -	    ao_ref dref;
> -	    ao_ref_init_from_ptr_and_size (&dref,
> -					   gimple_call_arg (call, 0),
> -					   NULL_TREE);
> -	    return refs_may_alias_p_1 (&dref, ref, false);
> -	  }
> -	/* These read memory pointed to by the first argument with size
> -	   in the third argument.  */
> -	case BUILT_IN_MEMCHR:
> -	  {
> -	    ao_ref dref;
> -	    ao_ref_init_from_ptr_and_size (&dref,
> -					   gimple_call_arg (call, 0),
> -					   gimple_call_arg (call, 2));
> -	    return refs_may_alias_p_1 (&dref, ref, false);
> -	  }
> -	/* These read memory pointed to by the first and second arguments.  */
> -	case BUILT_IN_STRSTR:
> -	case BUILT_IN_STRPBRK:
> -	  {
> -	    ao_ref dref;
> -	    ao_ref_init_from_ptr_and_size (&dref,
> -					   gimple_call_arg (call, 0),
> -					   NULL_TREE);
> -	    if (refs_may_alias_p_1 (&dref, ref, false))
> -	      return true;
> -	    ao_ref_init_from_ptr_and_size (&dref,
> -					   gimple_call_arg (call, 1),
> -					   NULL_TREE);
> -	    return refs_may_alias_p_1 (&dref, ref, false);
> -	  }
> -
> -	/* The following builtins do not read from memory.  */
> -	case BUILT_IN_FREE:
> -	case BUILT_IN_MALLOC:
> -	case BUILT_IN_POSIX_MEMALIGN:
> -	case BUILT_IN_ALIGNED_ALLOC:
> -	case BUILT_IN_CALLOC:
> -	CASE_BUILT_IN_ALLOCA:
> -	case BUILT_IN_STACK_SAVE:
> -	case BUILT_IN_STACK_RESTORE:
> -	case BUILT_IN_MEMSET:
> -	case BUILT_IN_TM_MEMSET:
> -	case BUILT_IN_MEMSET_CHK:
> -	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_SINCOS:
> -	case BUILT_IN_SINCOSF:
> -	case BUILT_IN_SINCOSL:
> -	case BUILT_IN_ASSUME_ALIGNED:
> -	case BUILT_IN_VA_END:
> +      && gimple_call_builtin_p (call, BUILT_IN_NORMAL)
> +      && (ao_classify_builtin (callee, &info)))
> +    {
> +      if (info.flags & AO_FUNCTION_BARRIER)
> +	return true;
> +      if (info.num_param_reads >= 0)
> +	{
> +	  for (int i = 0; i < info.num_param_reads; i++)
> +	    {
> +	      ao_ref dref;
> +	      tree size = NULL_TREE;
> +
> +	      gcc_checking_assert (info.reads[i].size_param
> +				   != info.reads[i].param);
> +	      if (info.reads[i].size_param != -1)
> +		size = gimple_call_arg (call, info.reads[i].size);
> +	      else if (info.reads[i].size)
> +		size = build_int_cst (size_type_node, info.reads[i].size);
> +	      ao_ref_init_from_ptr_and_size (&dref,
> +					     gimple_call_arg
> +						 (call,
> +						  info.reads[i].param),
> +					     size);
> +	      if (refs_may_alias_p_1 (&dref, ref, tbaa_p))
> +		return true;
> +	    }
>  	  return false;
> -	/* __sync_* builtins and some OpenMP builtins act as threading
> -	   barriers.  */
> -#undef DEF_SYNC_BUILTIN
> -#define DEF_SYNC_BUILTIN(ENUM, NAME, TYPE, ATTRS) case ENUM:
> -#include "sync-builtins.def"
> -#undef DEF_SYNC_BUILTIN
> -	case BUILT_IN_GOMP_ATOMIC_START:
> -	case BUILT_IN_GOMP_ATOMIC_END:
> -	case BUILT_IN_GOMP_BARRIER:
> -	case BUILT_IN_GOMP_BARRIER_CANCEL:
> -	case BUILT_IN_GOMP_TASKWAIT:
> -	case BUILT_IN_GOMP_TASKGROUP_END:
> -	case BUILT_IN_GOMP_CRITICAL_START:
> -	case BUILT_IN_GOMP_CRITICAL_END:
> -	case BUILT_IN_GOMP_CRITICAL_NAME_START:
> -	case BUILT_IN_GOMP_CRITICAL_NAME_END:
> -	case BUILT_IN_GOMP_LOOP_END:
> -	case BUILT_IN_GOMP_LOOP_END_CANCEL:
> -	case BUILT_IN_GOMP_ORDERED_START:
> -	case BUILT_IN_GOMP_ORDERED_END:
> -	case BUILT_IN_GOMP_SECTIONS_END:
> -	case BUILT_IN_GOMP_SECTIONS_END_CANCEL:
> -	case BUILT_IN_GOMP_SINGLE_COPY_START:
> -	case BUILT_IN_GOMP_SINGLE_COPY_END:
> -	  return true;
> -
> -	default:
> -	  /* Fallthru to general call handling.  */;
> -      }
> +	}
> +    }
>  
>    /* Check if base is a global static variable that is not read
>       by the function.  */
> @@ -2961,7 +3280,9 @@ call_may_clobber_ref_p_1 (gcall *call, ao_ref *ref, bool tbaa_p)
>  	  modref_summary *summary = get_modref_function_summary (node);
>  	  if (summary)
>  	    {
> -	      if (!modref_may_conflict (call, summary->stores, ref, tbaa_p))
> +	      if (!modref_may_conflict (call, summary->stores, ref, tbaa_p)
> +		  && (!summary->writes_errno
> +		      || !targetm.ref_may_alias_errno (ref)))
>  		{
>  		  alias_stats.modref_clobber_no_alias++;
>  		  if (dump_file && (dump_flags & TDF_DETAILS))
> @@ -3016,205 +3337,43 @@ call_may_clobber_ref_p_1 (gcall *call, ao_ref *ref, bool tbaa_p)
>        && SSA_NAME_POINTS_TO_READONLY_MEMORY (TREE_OPERAND (base, 0)))
>      return false;
>  
> +  struct ao_function_info info;
>    /* 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.  */
> +     escape points.  */
>    if (callee != NULL_TREE
> -      && gimple_call_builtin_p (call, 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_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:
> -	case BUILT_IN_MEMSET:
> -	case BUILT_IN_TM_MEMSET:
> -	CASE_BUILT_IN_TM_STORE (1):
> -	CASE_BUILT_IN_TM_STORE (2):
> -	CASE_BUILT_IN_TM_STORE (4):
> -	CASE_BUILT_IN_TM_STORE (8):
> -	CASE_BUILT_IN_TM_STORE (FLOAT):
> -	CASE_BUILT_IN_TM_STORE (DOUBLE):
> -	CASE_BUILT_IN_TM_STORE (LDOUBLE):
> -	CASE_BUILT_IN_TM_STORE (M64):
> -	CASE_BUILT_IN_TM_STORE (M128):
> -	CASE_BUILT_IN_TM_STORE (M256):
> -	case BUILT_IN_TM_MEMCPY:
> -	case BUILT_IN_TM_MEMMOVE:
> -	  {
> -	    ao_ref dref;
> -	    tree size = NULL_TREE;
> -	    /* Don't pass in size for strncat, as the maximum size
> -	       is strlen (dest) + n + 1 instead of n, resp.
> -	       n + 1 at dest + strlen (dest), but strlen (dest) isn't
> -	       known.  */
> -	    if (gimple_call_num_args (call) == 3
> -		&& DECL_FUNCTION_CODE (callee) != BUILT_IN_STRNCAT)
> -	      size = gimple_call_arg (call, 2);
> -	    ao_ref_init_from_ptr_and_size (&dref,
> -					   gimple_call_arg (call, 0),
> -					   size);
> -	    return refs_may_alias_p_1 (&dref, ref, false);
> -	  }
> -	case BUILT_IN_STRCPY_CHK:
> -	case BUILT_IN_STRNCPY_CHK:
> -	case BUILT_IN_MEMCPY_CHK:
> -	case BUILT_IN_MEMMOVE_CHK:
> -	case BUILT_IN_MEMPCPY_CHK:
> -	case BUILT_IN_STPCPY_CHK:
> -	case BUILT_IN_STPNCPY_CHK:
> -	case BUILT_IN_STRCAT_CHK:
> -	case BUILT_IN_STRNCAT_CHK:
> -	case BUILT_IN_MEMSET_CHK:
> -	  {
> -	    ao_ref dref;
> -	    tree size = NULL_TREE;
> -	    /* Don't pass in size for __strncat_chk, as the maximum size
> -	       is strlen (dest) + n + 1 instead of n, resp.
> -	       n + 1 at dest + strlen (dest), but strlen (dest) isn't
> -	       known.  */
> -	    if (gimple_call_num_args (call) == 4
> -		&& DECL_FUNCTION_CODE (callee) != BUILT_IN_STRNCAT_CHK)
> -	      size = gimple_call_arg (call, 2);
> -	    ao_ref_init_from_ptr_and_size (&dref,
> -					   gimple_call_arg (call, 0),
> -					   size);
> -	    return refs_may_alias_p_1 (&dref, ref, false);
> -	  }
> -	case BUILT_IN_BCOPY:
> -	  {
> -	    ao_ref dref;
> -	    tree size = gimple_call_arg (call, 2);
> -	    ao_ref_init_from_ptr_and_size (&dref,
> -					   gimple_call_arg (call, 1),
> -					   size);
> -	    return refs_may_alias_p_1 (&dref, ref, false);
> -	  }
> -	/* Allocating memory does not have any side-effects apart from
> -	   being the definition point for the pointer.  */
> -	case BUILT_IN_MALLOC:
> -	case BUILT_IN_ALIGNED_ALLOC:
> -	case BUILT_IN_CALLOC:
> -	case BUILT_IN_STRDUP:
> -	case BUILT_IN_STRNDUP:
> -	  /* Unix98 specifies that errno is set on allocation failure.  */
> -	  if (flag_errno_math
> -	      && targetm.ref_may_alias_errno (ref))
> -	    return true;
> -	  return false;
> -	case BUILT_IN_STACK_SAVE:
> -	CASE_BUILT_IN_ALLOCA:
> -	case BUILT_IN_ASSUME_ALIGNED:
> +      && gimple_call_builtin_p (call, BUILT_IN_NORMAL)
> +      && (ao_classify_builtin (callee, &info)))
> +    {
> +      if (info.flags & AO_FUNCTION_BARRIER)
> +	return true;
> +      if ((info.flags & AO_FUNCTION_ERRNO)
> +	  && flag_errno_math
> +	  && targetm.ref_may_alias_errno (ref))
> +	return true;
> +      if (info.num_param_writes >= 0)
> +	{
> +	  for (int i = 0; i < info.num_param_writes; i++)
> +	    {
> +	      ao_ref dref;
> +	      tree size = NULL_TREE;
> +
> +	      gcc_checking_assert (info.writes[i].size_param
> +				   != info.writes[i].param);
> +	      if (info.writes[i].size_param != -1)
> +		size = gimple_call_arg (call, info.writes[i].size_param);
> +	      else if (info.writes[i].size)
> +		size = build_int_cst (size_type_node, info.writes[i].size);
> +	      ao_ref_init_from_ptr_and_size (&dref,
> +					     gimple_call_arg
> +						 (call,
> +						  info.writes[i].param),
> +					     size);
> +	      if (refs_may_alias_p_1 (&dref, ref, tbaa_p))
> +		return true;
> +	    }
>  	  return false;
> -	/* But posix_memalign stores a pointer into the memory pointed to
> -	   by its first argument.  */
> -	case BUILT_IN_POSIX_MEMALIGN:
> -	  {
> -	    tree ptrptr = gimple_call_arg (call, 0);
> -	    ao_ref dref;
> -	    ao_ref_init_from_ptr_and_size (&dref, ptrptr,
> -					   TYPE_SIZE_UNIT (ptr_type_node));
> -	    return (refs_may_alias_p_1 (&dref, ref, false)
> -		    || (flag_errno_math
> -			&& targetm.ref_may_alias_errno (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.  */
> -	case BUILT_IN_FREE:
> -	case BUILT_IN_VA_END:
> -	  {
> -	    tree ptr = gimple_call_arg (call, 0);
> -	    return ptr_deref_may_alias_ref_p_1 (ptr, ref);
> -	  }
> -	/* Realloc serves both as allocation point and deallocation point.  */
> -	case BUILT_IN_REALLOC:
> -	  {
> -	    tree ptr = gimple_call_arg (call, 0);
> -	    /* Unix98 specifies that errno is set on allocation failure.  */
> -	    return ((flag_errno_math
> -		     && targetm.ref_may_alias_errno (ref))
> -		    || ptr_deref_may_alias_ref_p_1 (ptr, ref));
> -	  }
> -	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:
> -	  {
> -	    tree out = gimple_call_arg (call, 1);
> -	    if (ptr_deref_may_alias_ref_p_1 (out, ref))
> -	      return true;
> -	    if (flag_errno_math)
> -	      break;
> -	    return false;
> -	  }
> -	case BUILT_IN_FREXP:
> -	case BUILT_IN_FREXPF:
> -	case BUILT_IN_FREXPL:
> -	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_1 (out, ref);
> -	  }
> -	case BUILT_IN_REMQUO:
> -	case BUILT_IN_REMQUOF:
> -	case BUILT_IN_REMQUOL:
> -	  {
> -	    tree out = gimple_call_arg (call, 2);
> -	    if (ptr_deref_may_alias_ref_p_1 (out, ref))
> -	      return true;
> -	    if (flag_errno_math)
> -	      break;
> -	    return false;
> -	  }
> -	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);
> -	    return (ptr_deref_may_alias_ref_p_1 (sin, ref)
> -		    || ptr_deref_may_alias_ref_p_1 (cos, ref));
> -	  }
> -	/* __sync_* builtins and some OpenMP builtins act as threading
> -	   barriers.  */
> -#undef DEF_SYNC_BUILTIN
> -#define DEF_SYNC_BUILTIN(ENUM, NAME, TYPE, ATTRS) case ENUM:
> -#include "sync-builtins.def"
> -#undef DEF_SYNC_BUILTIN
> -	case BUILT_IN_GOMP_ATOMIC_START:
> -	case BUILT_IN_GOMP_ATOMIC_END:
> -	case BUILT_IN_GOMP_BARRIER:
> -	case BUILT_IN_GOMP_BARRIER_CANCEL:
> -	case BUILT_IN_GOMP_TASKWAIT:
> -	case BUILT_IN_GOMP_TASKGROUP_END:
> -	case BUILT_IN_GOMP_CRITICAL_START:
> -	case BUILT_IN_GOMP_CRITICAL_END:
> -	case BUILT_IN_GOMP_CRITICAL_NAME_START:
> -	case BUILT_IN_GOMP_CRITICAL_NAME_END:
> -	case BUILT_IN_GOMP_LOOP_END:
> -	case BUILT_IN_GOMP_LOOP_END_CANCEL:
> -	case BUILT_IN_GOMP_ORDERED_START:
> -	case BUILT_IN_GOMP_ORDERED_END:
> -	case BUILT_IN_GOMP_SECTIONS_END:
> -	case BUILT_IN_GOMP_SECTIONS_END_CANCEL:
> -	case BUILT_IN_GOMP_SINGLE_COPY_START:
> -	case BUILT_IN_GOMP_SINGLE_COPY_END:
> -	  return true;
> -	default:
> -	  /* Fallthru to general call handling.  */;
> -      }
> +	}
> +    }
>  
>    /* Check if base is a global static variable that is not written
>       by the function.  */
>
Jan Hubicka Sept. 28, 2020, 8:32 a.m. UTC | #2
> On Mon, 28 Sep 2020, Jan Hubicka wrote:
> 
> > Hi,
> > ipa-reference, ipa-pure-const and ipa-modref could use the knowledge
> > about bulitins which is currently harwired into
> > ref_maybe_used_by_call_p_1, call_may_clobber_ref_p_1 and the PTA
> > computation.  This patch breaks out logic implemented in the first two
> > into a form of a simple descriptor that can be used by the IPA passes
> > (and other code).
> > 
> > I was considering an option of putting this into def file but I do not think
> > it is feasible without cluttering it quite a lot.
> > 
> > For ipa-modref I implemented dump informing about missing builtins. strlen,
> > sqrt and exp seems common offenders, but that can be handled incrementally
> > if the approach looks reasonable.
> > I would also look adding the description for PTA (perhaps with some
> > special cases remainig since it is more ad-hoc)
> > 
> > Bootstrapped/regtested x86_64-linux, OK?
> 
> Hmm, this looks awfully similar to fn-spec handling done in
> process_args via gimple_call_arg_flags ()?

Kind of similar (I was also looking into this, since with modref we
could detect noescape attribute rather easily).

I am not quite sure the attribute machinery overlaps that well with what
we do with builtins.  tree-ssa-alias only use gimple_call_arg_flags to
detect that pure/const fuction does not use its argument.  We would need
to invent how to add info that non pure/const function only access the
argument according to fn spec, add way to represent sizes of accesses
and how to handle errno.

Honza
> 
> > gcc/ChangeLog:
> > 
> > 2020-09-28  Jan Hubicka  <hubicka@ucw.cz>
> > 
> > 	* tree-ssa-alias.c (ao_classify_builtin): New function commonizing
> > 	logic from ...
> > 	(ref_maybe_used_by_call_p_1): ... here.
> > 	(call_may_clobber_ref_p_1): ... and here.
> > 	* tree-ssa-alias.h (enum ao_function_flags): New enum.
> > 	(struct ao_function_info): New structure.
> > 	(ao_classify_builtin): Declare.
> > 
> > diff --git a/gcc/tree-ssa-alias.h b/gcc/tree-ssa-alias.h
> > index 1dd02c0ea62..eecb8da6dd7 100644
> > --- a/gcc/tree-ssa-alias.h
> > +++ b/gcc/tree-ssa-alias.h
> > @@ -108,6 +108,33 @@ ao_ref::max_size_known_p () const
> >    return known_size_p (max_size);
> >  }
> >  
> > +/* Flags used in ao_function_info.  */
> > +
> > +enum ao_function_flags
> > +{
> > +  AO_FUNCTION_BARRIER = 1,
> > +  AO_FUNCTION_ERRNO = 2,
> > +};
> > +
> > +/* Describe side effects relevant for alias analysis of function call to
> > +   DECL.  */
> > +
> > +struct ao_function_info
> > +{
> > +  int num_param_reads;  /* Number of parameters function reads from,
> > +			   -1 if reads are unknown.  */
> > +  struct ao_access_info
> > +    {
> > +      char param; 	/* Index of parameter read/written from.  */
> > +      char size_param;	/* Index of parameter specifying size of the access,
> > +			   -1 if unknown.  */
> > +      char size;	/* Size of access if known, 0 if unknown.  */
> > +    } reads[2];
> > +  int num_param_writes;
> > +  struct ao_access_info writes[2];
> > +  enum ao_function_flags flags;
> > +};
> > +
> >  /* In tree-ssa-alias.c  */
> >  extern void ao_ref_init (ao_ref *, tree);
> >  extern void ao_ref_init_from_ptr_and_size (ao_ref *, tree, tree);
> > @@ -158,6 +185,7 @@ extern void debug (pt_solution *ptr);
> >  extern void dump_points_to_info_for (FILE *, tree);
> >  extern void debug_points_to_info_for (tree);
> >  extern void dump_alias_stats (FILE *);
> > +extern bool ao_classify_builtin (tree callee, ao_function_info *info);
> >  
> >  
> >  /* In tree-ssa-structalias.c  */
> > diff --git a/gcc/tree-ssa-alias.c b/gcc/tree-ssa-alias.c
> > index fe390d4ffbe..c182e7bb39c 100644
> > --- a/gcc/tree-ssa-alias.c
> > +++ b/gcc/tree-ssa-alias.c
> > @@ -2503,6 +2503,507 @@ modref_may_conflict (const gimple *stmt,
> >    return false;
> >  }
> >  
> > +/* If CALLEE has known side effects, fill in INFO and return true.
> > +   See tree-ssa-structalias.c:find_func_aliases
> > +   for the list of builtins we might need to handle here.  */
> > +
> > +bool
> > +ao_classify_builtin (tree callee, ao_function_info *info)
> > +{
> > +  built_in_function code = DECL_FUNCTION_CODE (callee);
> > +
> > +  switch (code)
> > +    {
> > +      /* All the following functions read memory pointed to by
> > +	 their second argument and write memory pointed to by first
> > +	 argument.
> > +	 strcat/strncat additionally reads memory pointed to by the first
> > +	 argument.  */
> > +      case BUILT_IN_STRCAT:
> > +	{
> > +	  const static struct ao_function_info ret_info
> > +	       = {
> > +		    2,				/* num_param_reads.  */
> > +
> > +		    /* Reads and write descriptors are triples containing:
> > +		       - index of parameter read
> > +		       - index of parameter specifying access size
> > +			 (-1 if unknown)
> > +		       - access size in bytes (0 if unkown).  */
> > +
> > +		    {{0, -1, 0}, {1, -1, 0}},	/* Param read.  */
> > +		    1,				/* num_param_writes.  */
> > +		    {{0, -1, 0}},		/* Param written.  */
> > +		    (ao_function_flags)0,	/* flags.  */
> > +		 };
> > +	  *info = ret_info;
> > +	  return true;
> > +	}
> > +      case BUILT_IN_STRNCAT:
> > +	{
> > +	  const static struct ao_function_info ret_info
> > +	       = {
> > +		    2,				/* num_param_reads.  */
> > +		    {{0, -1, 0}, {1, 2, 0}},	/* Param read.  */
> > +		    1,				/* num_param_writes.  */
> > +		    {{0, -1, 0}},		/* Param written.  */
> > +		    (ao_function_flags)0,	/* flags.  */
> > +		 };
> > +	  *info = ret_info;
> > +	  return true;
> > +	}
> > +      case BUILT_IN_STRCPY:
> > +      case BUILT_IN_STPCPY:
> > +	{
> > +	  const static struct ao_function_info ret_info
> > +	       = {
> > +		    1,				/* num_param_reads.  */
> > +		    {{1, -1, 0}},		/* Param read.  */
> > +		    1,				/* num_param_writes.  */
> > +		    {{0, -1, 0}},		/* Param written.  */
> > +		    (ao_function_flags)0,	/* flags.  */
> > +		 };
> > +	  *info = ret_info;
> > +	  return true;
> > +	}
> > +      case BUILT_IN_STRNCPY:
> > +      case BUILT_IN_MEMCPY:
> > +      case BUILT_IN_MEMMOVE:
> > +      case BUILT_IN_MEMPCPY:
> > +      case BUILT_IN_STPNCPY:
> > +      case BUILT_IN_TM_MEMCPY:
> > +      case BUILT_IN_TM_MEMMOVE:
> > +	{
> > +	  const static struct ao_function_info ret_info
> > +	       = {
> > +		    1,				/* num_param_reads.  */
> > +		    {{1, 2, 0}},		/* Param read.  */
> > +		    1,				/* num_param_writes.  */
> > +		    {{0, 2, 0}},		/* Param written.  */
> > +		    (ao_function_flags)0,	/* flags.  */
> > +		 };
> > +	  *info = ret_info;
> > +	  return true;
> > +	}
> > +      case BUILT_IN_STRCAT_CHK:
> > +	{
> > +	  const static struct ao_function_info ret_info
> > +	       = {
> > +		    2,				/* num_param_reads.  */
> > +		    {{0, -1, 0}, {1, -1, 0}},	/* Param read.  */
> > +		    1,				/* num_param_writes.  */
> > +		    {{0, -1, 0}},		/* Param written.  */
> > +		    (ao_function_flags)0,	/* flags.  */
> > +		 };
> > +	  *info = ret_info;
> > +	  return true;
> > +	}
> > +      case BUILT_IN_STRNCAT_CHK:
> > +	{
> > +	  const static struct ao_function_info ret_info
> > +	       = {
> > +		    2,				/* num_param_reads.  */
> > +		    {{0, -1, 0}, {1, 2, 0}},	/* Param read.  */
> > +		    1,				/* num_param_writes.  */
> > +		    {{0, -1, 0}},		/* Param written.  */
> > +		    (ao_function_flags)0,	/* flags.  */
> > +		 };
> > +	  *info = ret_info;
> > +	  return true;
> > +	}
> > +      case BUILT_IN_STRCPY_CHK:
> > +      case BUILT_IN_STPCPY_CHK:
> > +	{
> > +	  const static struct ao_function_info ret_info
> > +	       = {
> > +		    1,				/* num_param_reads.  */
> > +		    {{1, -1, 0}},		/* Param read.  */
> > +		    1,				/* num_param_writes.  */
> > +		    {{0, -1, 0}},		/* Param written.  */
> > +		    (ao_function_flags)0,	/* flags.  */
> > +		 };
> > +	  *info = ret_info;
> > +	  return true;
> > +	}
> > +      case BUILT_IN_STRNCPY_CHK:
> > +      case BUILT_IN_MEMCPY_CHK:
> > +      case BUILT_IN_MEMMOVE_CHK:
> > +      case BUILT_IN_MEMPCPY_CHK:
> > +      case BUILT_IN_STPNCPY_CHK:
> > +	{
> > +	  const static struct ao_function_info ret_info
> > +	       = {
> > +		    1,				/* num_param_reads.  */
> > +		    {{1, 2, 0}},		/* Param read.  */
> > +		    1,				/* num_param_writes.  */
> > +		    {{0, 2, 0}},		/* Param written.  */
> > +		    (ao_function_flags)0,	/* flags.  */
> > +		 };
> > +	  *info = ret_info;
> > +	  return true;
> > +	}
> > +      case BUILT_IN_BCOPY:
> > +	{
> > +	  const static struct ao_function_info ret_info
> > +	       = {
> > +		    1,				/* num_param_reads.  */
> > +		    {{0, 2, 0}},		/* Param read.  */
> > +		    1,				/* num_param_writes.  */
> > +		    {{1, 2, 0}},		/* Param written.  */
> > +		    (ao_function_flags)0,	/* flags.  */
> > +		 };
> > +	  *info = ret_info;
> > +	  return true;
> > +	}
> > +
> > +      /* The following functions read memory pointed to by their
> > +	 first argument.  */
> > +      CASE_BUILT_IN_TM_LOAD (1):
> > +      CASE_BUILT_IN_TM_LOAD (2):
> > +      CASE_BUILT_IN_TM_LOAD (4):
> > +      CASE_BUILT_IN_TM_LOAD (8):
> > +      CASE_BUILT_IN_TM_LOAD (FLOAT):
> > +      CASE_BUILT_IN_TM_LOAD (DOUBLE):
> > +      CASE_BUILT_IN_TM_LOAD (LDOUBLE):
> > +      CASE_BUILT_IN_TM_LOAD (M64):
> > +      CASE_BUILT_IN_TM_LOAD (M128):
> > +      CASE_BUILT_IN_TM_LOAD (M256):
> > +      case BUILT_IN_TM_LOG:
> > +      case BUILT_IN_TM_LOG_1:
> > +      case BUILT_IN_TM_LOG_2:
> > +      case BUILT_IN_TM_LOG_4:
> > +      case BUILT_IN_TM_LOG_8:
> > +      case BUILT_IN_TM_LOG_FLOAT:
> > +      case BUILT_IN_TM_LOG_DOUBLE:
> > +      case BUILT_IN_TM_LOG_LDOUBLE:
> > +      case BUILT_IN_TM_LOG_M64:
> > +      case BUILT_IN_TM_LOG_M128:
> > +      case BUILT_IN_TM_LOG_M256:
> > +
> > +      case BUILT_IN_INDEX:
> > +      case BUILT_IN_STRCHR:
> > +      case BUILT_IN_STRRCHR:
> > +	{
> > +	  const static struct ao_function_info ret_info
> > +	       = {
> > +		    1,				/* num_param_reads.  */
> > +		    /* TODO: For TM builtins size is known.  */
> > +		    {{0, -1, 0}},		/* Param read.  */
> > +		    0,				/* num_param_writes.  */
> > +		    {},				/* Param written.  */
> > +		    (ao_function_flags)0,	/* flags.  */
> > +		 };
> > +	  *info = ret_info;
> > +	  return true;
> > +	}
> > +
> > +      /* These read memory pointed to by the first argument.
> > +	 Allocating memory does not have any side-effects apart from
> > +	 being the definition point for the pointer.
> > +	 Unix98 specifies that errno is set on allocation failure.  */
> > +      case BUILT_IN_STRDUP:
> > +	{
> > +	  const static struct ao_function_info ret_info
> > +	       = {
> > +		    1,				/* num_param_reads.  */
> > +		    {{0, -1, 0}},		/* Param read.  */
> > +		    0,				/* num_param_writes.  */
> > +		    {},				/* Param written.  */
> > +		    AO_FUNCTION_ERRNO,		/* flags.  */
> > +		 };
> > +	  *info = ret_info;
> > +	  return true;
> > +	}
> > +      case BUILT_IN_STRNDUP:
> > +	{
> > +	  const static struct ao_function_info ret_info
> > +	       = {
> > +		    1,				/* num_param_reads.  */
> > +		    {{0, 1, 0}},		/* Param read.  */
> > +		    0,				/* num_param_writes.  */
> > +		    {},				/* Param written.  */
> > +		    AO_FUNCTION_ERRNO,		/* flags.  */
> > +		 };
> > +	  *info = ret_info;
> > +	  return true;
> > +	}
> > +      /* Allocating memory does not have any side-effects apart from
> > +	 being the definition point for the pointer.  */
> > +      case BUILT_IN_MALLOC:
> > +      case BUILT_IN_ALIGNED_ALLOC:
> > +      case BUILT_IN_CALLOC:
> > +	{
> > +	  const static struct ao_function_info ret_info
> > +	       = {
> > +		    0,				/* num_param_reads.  */
> > +		    {},				/* Param read.  */
> > +		    0,				/* num_param_writes.  */
> > +		    {},				/* Param written.  */
> > +		    AO_FUNCTION_ERRNO,		/* flags.  */
> > +		 };
> > +	  *info = ret_info;
> > +	  return true;
> > +	}
> > +      /* These read memory pointed to by the first argument with size
> > +	 in the third argument.  */
> > +      case BUILT_IN_MEMCHR:
> > +	{
> > +	  const static struct ao_function_info ret_info
> > +	       = {
> > +		    1,				/* num_param_reads.  */
> > +		    {{0, 2, 0}},		/* Param read.  */
> > +		    0,				/* num_param_writes.  */
> > +		    {},				/* Param written.  */
> > +		    (ao_function_flags)0,	/* flags.  */
> > +		 };
> > +	  *info = ret_info;
> > +	  return true;
> > +	}
> > +      /* These read memory pointed to by the first and second arguments.  */
> > +      case BUILT_IN_STRSTR:
> > +      case BUILT_IN_STRPBRK:
> > +	{
> > +	  static struct ao_function_info ret_info
> > +	       = {
> > +		    2,				/* num_param_reads.  */
> > +		    {{0, -1, 0}, {1, -1, 0}},	/* Param read.  */
> > +		    0,				/* num_param_writes.  */
> > +		    {},				/* Param written.  */
> > +		    (ao_function_flags)0,	/* flags.  */
> > +		 };
> > +	  *info = ret_info;
> > +	  return true;
> > +	}
> > +      /* Freeing memory kills the pointed-to memory.  More importantly
> > +	 the call has to serve as a barrier for moving loads and stores
> > +	 across it.  */
> > +      case BUILT_IN_FREE:
> > +      case BUILT_IN_VA_END:
> > +	{
> > +	  const static struct ao_function_info ret_info
> > +	       = {
> > +		    0,				/* num_param_reads.  */
> > +		    {},				/* Param read.  */
> > +		    1,				/* num_param_writes.  */
> > +		    {{0, -1, 0}},		/* Param written.  */
> > +		    (ao_function_flags)0,	/* flags.  */
> > +		 };
> > +	  *info = ret_info;
> > +	  return true;
> > +	}
> > +      /* Realloc serves both as allocation point and deallocation point.  */
> > +      case BUILT_IN_REALLOC:
> > +	{
> > +	  const static struct ao_function_info ret_info
> > +	       = {
> > +		    1,				/* num_param_reads.  */
> > +		    {{0, 1, 0}},		/* Param read.  */
> > +		    0,				/* num_param_writes.  */
> > +		    {{0, -1, 0}},		/* Param written.  */
> > +		    AO_FUNCTION_ERRNO,		/* flags.  */
> > +		 };
> > +	  *info = ret_info;
> > +	  return true;
> > +	}
> > +      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:
> > +	{
> > +	  const static struct ao_function_info ret_info
> > +	       = {
> > +		    0,				/* num_param_reads.  */
> > +		    {},				/* Param read.  */
> > +		    1,				/* num_param_writes.  */
> > +		    {{1, -1, 0}},		/* Param written.  */
> > +		    AO_FUNCTION_ERRNO,		/* flags.  */
> > +		 };
> > +	  *info = ret_info;
> > +	  return true;
> > +	}
> > +      case BUILT_IN_FREXP:
> > +      case BUILT_IN_FREXPF:
> > +      case BUILT_IN_FREXPL:
> > +      case BUILT_IN_MODF:
> > +      case BUILT_IN_MODFF:
> > +      case BUILT_IN_MODFL:
> > +	{
> > +	  const static struct ao_function_info ret_info
> > +	       = {
> > +		    0,				/* num_param_reads.  */
> > +		    {},				/* Param read.  */
> > +		    1,				/* num_param_writes.  */
> > +		    {{1, -1, 0}},		/* Param written.  */
> > +		    (ao_function_flags)0,	/* flags.  */
> > +		 };
> > +	  *info = ret_info;
> > +	  return true;
> > +	}
> > +      case BUILT_IN_REMQUO:
> > +      case BUILT_IN_REMQUOF:
> > +      case BUILT_IN_REMQUOL:
> > +	{
> > +	  const static struct ao_function_info ret_info
> > +	       = {
> > +		    0,				/* num_param_reads.  */
> > +		    {},				/* Param read.  */
> > +		    1,				/* num_param_writes.  */
> > +		    {{2, -1, 0}},		/* Param written.  */
> > +		    (ao_function_flags)0,	/* flags.  */
> > +		 };
> > +	  *info = ret_info;
> > +	  return true;
> > +	}
> > +      case BUILT_IN_SINCOS:
> > +      case BUILT_IN_SINCOSF:
> > +      case BUILT_IN_SINCOSL:
> > +	{
> > +	  static struct ao_function_info ret_info
> > +	       = {
> > +		    0,				/* num_param_reads.  */
> > +		    {},				/* Param read.  */
> > +		    1,				/* num_param_writes.  */
> > +		    {{1, -1, 0}, {2, -1, 0}},	/* Param written.  */
> > +		    (ao_function_flags)0,	/* flags.  */
> > +		 };
> > +	  tree type = float_ptr_type_node;
> > +	  if (code == BUILT_IN_SINCOS)
> > +	    type = double_ptr_type_node;
> > +	  else
> > +	    type = long_double_ptr_type_node;
> > +	  ret_info.writes[0].size = ret_info.writes[1].size
> > +		 = tree_to_uhwi (TYPE_SIZE_UNIT (type));
> > +	  *info = ret_info;
> > +	  return true;
> > +	}
> > +      case BUILT_IN_MEMSET:
> > +      case BUILT_IN_MEMSET_CHK:
> > +      case BUILT_IN_TM_MEMSET:
> > +	{
> > +	  const static struct ao_function_info ret_info
> > +	       = {
> > +		    0,				/* num_param_reads.  */
> > +		    {},				/* Param read.  */
> > +		    1,				/* num_param_writes.  */
> > +		    {0, 2, 0},			/* Param written.  */
> > +		    (ao_function_flags)0,	/* flags.  */
> > +		 };
> > +	  *info = ret_info;
> > +	  return true;
> > +	}
> > +      CASE_BUILT_IN_TM_STORE (1):
> > +      CASE_BUILT_IN_TM_STORE (2):
> > +      CASE_BUILT_IN_TM_STORE (4):
> > +      CASE_BUILT_IN_TM_STORE (8):
> > +      CASE_BUILT_IN_TM_STORE (FLOAT):
> > +      CASE_BUILT_IN_TM_STORE (DOUBLE):
> > +      CASE_BUILT_IN_TM_STORE (LDOUBLE):
> > +      CASE_BUILT_IN_TM_STORE (M64):
> > +      CASE_BUILT_IN_TM_STORE (M128):
> > +      CASE_BUILT_IN_TM_STORE (M256):
> > +	{
> > +	  const static struct ao_function_info ret_info
> > +	       = {
> > +		    0,				/* num_param_reads.  */
> > +		    {},				/* Param read.  */
> > +		    1,				/* num_param_writes.  */
> > +		    /* TODO: Size is known.  */
> > +		    {0, -1, 0},			/* Param written.  */
> > +		    (ao_function_flags)0,	/* flags.  */
> > +		 };
> > +	  *info = ret_info;
> > +	  return true;
> > +	}
> > +      case BUILT_IN_STACK_SAVE:
> > +      CASE_BUILT_IN_ALLOCA:
> > +      case BUILT_IN_ASSUME_ALIGNED:
> > +	{
> > +	  const static struct ao_function_info ret_info
> > +	       = {
> > +		    0,				/* num_param_reads.  */
> > +		    {},				/* Param read.  */
> > +		    0,				/* num_param_writes.  */
> > +		    {},				/* Param written.  */
> > +		    (ao_function_flags)0,	/* flags.  */
> > +		 };
> > +	  *info = ret_info;
> > +	  return true;
> > +	}
> > +      /* But posix_memalign stores a pointer into the memory pointed to
> > +	 by its first argument.  */
> > +      case BUILT_IN_POSIX_MEMALIGN:
> > +	{
> > +	  static struct ao_function_info ret_info
> > +	       = {
> > +		    0,				/* num_param_reads.  */
> > +		    {},				/* Param read.  */
> > +		    0,				/* num_param_writes.  */
> > +		    {{0, -1, 0}},		/* Param written.  */
> > +		    AO_FUNCTION_ERRNO,		/* flags.  */
> > +		 };
> > +	  ret_info.writes[0].size
> > +		 = tree_to_uhwi (TYPE_SIZE_UNIT (ptr_type_node));
> > +	  *info = ret_info;
> > +	  return true;
> > +	}
> > +      /* The following builtins do not read from memory.  */
> > +      case BUILT_IN_STACK_RESTORE:
> > +	{
> > +	  const static struct ao_function_info ret_info
> > +	       = {
> > +		    0,				/* num_param_reads.  */
> > +		    {},				/* Param read.  */
> > +		    0,				/* num_param_writes.  */
> > +		    {},				/* Param written.  */
> > +		    (ao_function_flags)0,	/* flags.  */
> > +		 };
> > +	  *info = ret_info;
> > +	  return true;
> > +	}
> > +      /* __sync_* builtins and some OpenMP builtins act as threading
> > +	 barriers.  */
> > +#undef DEF_SYNC_BUILTIN
> > +#define DEF_SYNC_BUILTIN(ENUM, NAME, TYPE, ATTRS) case ENUM:
> > +#include "sync-builtins.def"
> > +#undef DEF_SYNC_BUILTIN
> > +      case BUILT_IN_GOMP_ATOMIC_START:
> > +      case BUILT_IN_GOMP_ATOMIC_END:
> > +      case BUILT_IN_GOMP_BARRIER:
> > +      case BUILT_IN_GOMP_BARRIER_CANCEL:
> > +      case BUILT_IN_GOMP_TASKWAIT:
> > +      case BUILT_IN_GOMP_TASKGROUP_END:
> > +      case BUILT_IN_GOMP_CRITICAL_START:
> > +      case BUILT_IN_GOMP_CRITICAL_END:
> > +      case BUILT_IN_GOMP_CRITICAL_NAME_START:
> > +      case BUILT_IN_GOMP_CRITICAL_NAME_END:
> > +      case BUILT_IN_GOMP_LOOP_END:
> > +      case BUILT_IN_GOMP_LOOP_END_CANCEL:
> > +      case BUILT_IN_GOMP_ORDERED_START:
> > +      case BUILT_IN_GOMP_ORDERED_END:
> > +      case BUILT_IN_GOMP_SECTIONS_END:
> > +      case BUILT_IN_GOMP_SECTIONS_END_CANCEL:
> > +      case BUILT_IN_GOMP_SINGLE_COPY_START:
> > +      case BUILT_IN_GOMP_SINGLE_COPY_END:
> > +	{
> > +	  const static struct ao_function_info ret_info
> > +	       = {
> > +		    -1,				/* num_param_reads.  */
> > +		    {},				/* Param read.  */
> > +		    -1,				/* num_param_writes.  */
> > +		    {},				/* Param written.  */
> > +		    AO_FUNCTION_BARRIER,	/* flags.  */
> > +		 };
> > +	  *info = ret_info;
> > +	  return true;
> > +	}
> > +
> > +      default:
> > +	return false;
> > +    }
> > +}
> > +
> >  /* If the call CALL may use the memory reference REF return true,
> >     otherwise return false.  */
> >  
> > @@ -2574,219 +3075,37 @@ ref_maybe_used_by_call_p_1 (gcall *call, ao_ref *ref, bool tbaa_p)
> >    /* 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.  */
> > +  struct ao_function_info info;
> >    if (callee != NULL_TREE
> > -      && gimple_call_builtin_p (call, BUILT_IN_NORMAL))
> > -    switch (DECL_FUNCTION_CODE (callee))
> > -      {
> > -	/* All the following functions read memory pointed to by
> > -	   their second argument.  strcat/strncat additionally
> > -	   reads memory pointed to by the first argument.  */
> > -	case BUILT_IN_STRCAT:
> > -	case BUILT_IN_STRNCAT:
> > -	  {
> > -	    ao_ref dref;
> > -	    ao_ref_init_from_ptr_and_size (&dref,
> > -					   gimple_call_arg (call, 0),
> > -					   NULL_TREE);
> > -	    if (refs_may_alias_p_1 (&dref, ref, false))
> > -	      return true;
> > -	  }
> > -	  /* FALLTHRU */
> > -	case BUILT_IN_STRCPY:
> > -	case BUILT_IN_STRNCPY:
> > -	case BUILT_IN_MEMCPY:
> > -	case BUILT_IN_MEMMOVE:
> > -	case BUILT_IN_MEMPCPY:
> > -	case BUILT_IN_STPCPY:
> > -	case BUILT_IN_STPNCPY:
> > -	case BUILT_IN_TM_MEMCPY:
> > -	case BUILT_IN_TM_MEMMOVE:
> > -	  {
> > -	    ao_ref dref;
> > -	    tree size = NULL_TREE;
> > -	    if (gimple_call_num_args (call) == 3)
> > -	      size = gimple_call_arg (call, 2);
> > -	    ao_ref_init_from_ptr_and_size (&dref,
> > -					   gimple_call_arg (call, 1),
> > -					   size);
> > -	    return refs_may_alias_p_1 (&dref, ref, false);
> > -	  }
> > -	case BUILT_IN_STRCAT_CHK:
> > -	case BUILT_IN_STRNCAT_CHK:
> > -	  {
> > -	    ao_ref dref;
> > -	    ao_ref_init_from_ptr_and_size (&dref,
> > -					   gimple_call_arg (call, 0),
> > -					   NULL_TREE);
> > -	    if (refs_may_alias_p_1 (&dref, ref, false))
> > -	      return true;
> > -	  }
> > -	  /* FALLTHRU */
> > -	case BUILT_IN_STRCPY_CHK:
> > -	case BUILT_IN_STRNCPY_CHK:
> > -	case BUILT_IN_MEMCPY_CHK:
> > -	case BUILT_IN_MEMMOVE_CHK:
> > -	case BUILT_IN_MEMPCPY_CHK:
> > -	case BUILT_IN_STPCPY_CHK:
> > -	case BUILT_IN_STPNCPY_CHK:
> > -	  {
> > -	    ao_ref dref;
> > -	    tree size = NULL_TREE;
> > -	    if (gimple_call_num_args (call) == 4)
> > -	      size = gimple_call_arg (call, 2);
> > -	    ao_ref_init_from_ptr_and_size (&dref,
> > -					   gimple_call_arg (call, 1),
> > -					   size);
> > -	    return refs_may_alias_p_1 (&dref, ref, false);
> > -	  }
> > -	case BUILT_IN_BCOPY:
> > -	  {
> > -	    ao_ref dref;
> > -	    tree size = gimple_call_arg (call, 2);
> > -	    ao_ref_init_from_ptr_and_size (&dref,
> > -					   gimple_call_arg (call, 0),
> > -					   size);
> > -	    return refs_may_alias_p_1 (&dref, ref, false);
> > -	  }
> > -
> > -	/* The following functions read memory pointed to by their
> > -	   first argument.  */
> > -	CASE_BUILT_IN_TM_LOAD (1):
> > -	CASE_BUILT_IN_TM_LOAD (2):
> > -	CASE_BUILT_IN_TM_LOAD (4):
> > -	CASE_BUILT_IN_TM_LOAD (8):
> > -	CASE_BUILT_IN_TM_LOAD (FLOAT):
> > -	CASE_BUILT_IN_TM_LOAD (DOUBLE):
> > -	CASE_BUILT_IN_TM_LOAD (LDOUBLE):
> > -	CASE_BUILT_IN_TM_LOAD (M64):
> > -	CASE_BUILT_IN_TM_LOAD (M128):
> > -	CASE_BUILT_IN_TM_LOAD (M256):
> > -	case BUILT_IN_TM_LOG:
> > -	case BUILT_IN_TM_LOG_1:
> > -	case BUILT_IN_TM_LOG_2:
> > -	case BUILT_IN_TM_LOG_4:
> > -	case BUILT_IN_TM_LOG_8:
> > -	case BUILT_IN_TM_LOG_FLOAT:
> > -	case BUILT_IN_TM_LOG_DOUBLE:
> > -	case BUILT_IN_TM_LOG_LDOUBLE:
> > -	case BUILT_IN_TM_LOG_M64:
> > -	case BUILT_IN_TM_LOG_M128:
> > -	case BUILT_IN_TM_LOG_M256:
> > -	  return ptr_deref_may_alias_ref_p_1 (gimple_call_arg (call, 0), ref);
> > -
> > -	/* These read memory pointed to by the first argument.  */
> > -	case BUILT_IN_STRDUP:
> > -	case BUILT_IN_STRNDUP:
> > -	case BUILT_IN_REALLOC:
> > -	  {
> > -	    ao_ref dref;
> > -	    tree size = NULL_TREE;
> > -	    if (gimple_call_num_args (call) == 2)
> > -	      size = gimple_call_arg (call, 1);
> > -	    ao_ref_init_from_ptr_and_size (&dref,
> > -					   gimple_call_arg (call, 0),
> > -					   size);
> > -	    return refs_may_alias_p_1 (&dref, ref, false);
> > -	  }
> > -	/* These read memory pointed to by the first argument.  */
> > -	case BUILT_IN_INDEX:
> > -	case BUILT_IN_STRCHR:
> > -	case BUILT_IN_STRRCHR:
> > -	  {
> > -	    ao_ref dref;
> > -	    ao_ref_init_from_ptr_and_size (&dref,
> > -					   gimple_call_arg (call, 0),
> > -					   NULL_TREE);
> > -	    return refs_may_alias_p_1 (&dref, ref, false);
> > -	  }
> > -	/* These read memory pointed to by the first argument with size
> > -	   in the third argument.  */
> > -	case BUILT_IN_MEMCHR:
> > -	  {
> > -	    ao_ref dref;
> > -	    ao_ref_init_from_ptr_and_size (&dref,
> > -					   gimple_call_arg (call, 0),
> > -					   gimple_call_arg (call, 2));
> > -	    return refs_may_alias_p_1 (&dref, ref, false);
> > -	  }
> > -	/* These read memory pointed to by the first and second arguments.  */
> > -	case BUILT_IN_STRSTR:
> > -	case BUILT_IN_STRPBRK:
> > -	  {
> > -	    ao_ref dref;
> > -	    ao_ref_init_from_ptr_and_size (&dref,
> > -					   gimple_call_arg (call, 0),
> > -					   NULL_TREE);
> > -	    if (refs_may_alias_p_1 (&dref, ref, false))
> > -	      return true;
> > -	    ao_ref_init_from_ptr_and_size (&dref,
> > -					   gimple_call_arg (call, 1),
> > -					   NULL_TREE);
> > -	    return refs_may_alias_p_1 (&dref, ref, false);
> > -	  }
> > -
> > -	/* The following builtins do not read from memory.  */
> > -	case BUILT_IN_FREE:
> > -	case BUILT_IN_MALLOC:
> > -	case BUILT_IN_POSIX_MEMALIGN:
> > -	case BUILT_IN_ALIGNED_ALLOC:
> > -	case BUILT_IN_CALLOC:
> > -	CASE_BUILT_IN_ALLOCA:
> > -	case BUILT_IN_STACK_SAVE:
> > -	case BUILT_IN_STACK_RESTORE:
> > -	case BUILT_IN_MEMSET:
> > -	case BUILT_IN_TM_MEMSET:
> > -	case BUILT_IN_MEMSET_CHK:
> > -	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_SINCOS:
> > -	case BUILT_IN_SINCOSF:
> > -	case BUILT_IN_SINCOSL:
> > -	case BUILT_IN_ASSUME_ALIGNED:
> > -	case BUILT_IN_VA_END:
> > +      && gimple_call_builtin_p (call, BUILT_IN_NORMAL)
> > +      && (ao_classify_builtin (callee, &info)))
> > +    {
> > +      if (info.flags & AO_FUNCTION_BARRIER)
> > +	return true;
> > +      if (info.num_param_reads >= 0)
> > +	{
> > +	  for (int i = 0; i < info.num_param_reads; i++)
> > +	    {
> > +	      ao_ref dref;
> > +	      tree size = NULL_TREE;
> > +
> > +	      gcc_checking_assert (info.reads[i].size_param
> > +				   != info.reads[i].param);
> > +	      if (info.reads[i].size_param != -1)
> > +		size = gimple_call_arg (call, info.reads[i].size);
> > +	      else if (info.reads[i].size)
> > +		size = build_int_cst (size_type_node, info.reads[i].size);
> > +	      ao_ref_init_from_ptr_and_size (&dref,
> > +					     gimple_call_arg
> > +						 (call,
> > +						  info.reads[i].param),
> > +					     size);
> > +	      if (refs_may_alias_p_1 (&dref, ref, tbaa_p))
> > +		return true;
> > +	    }
> >  	  return false;
> > -	/* __sync_* builtins and some OpenMP builtins act as threading
> > -	   barriers.  */
> > -#undef DEF_SYNC_BUILTIN
> > -#define DEF_SYNC_BUILTIN(ENUM, NAME, TYPE, ATTRS) case ENUM:
> > -#include "sync-builtins.def"
> > -#undef DEF_SYNC_BUILTIN
> > -	case BUILT_IN_GOMP_ATOMIC_START:
> > -	case BUILT_IN_GOMP_ATOMIC_END:
> > -	case BUILT_IN_GOMP_BARRIER:
> > -	case BUILT_IN_GOMP_BARRIER_CANCEL:
> > -	case BUILT_IN_GOMP_TASKWAIT:
> > -	case BUILT_IN_GOMP_TASKGROUP_END:
> > -	case BUILT_IN_GOMP_CRITICAL_START:
> > -	case BUILT_IN_GOMP_CRITICAL_END:
> > -	case BUILT_IN_GOMP_CRITICAL_NAME_START:
> > -	case BUILT_IN_GOMP_CRITICAL_NAME_END:
> > -	case BUILT_IN_GOMP_LOOP_END:
> > -	case BUILT_IN_GOMP_LOOP_END_CANCEL:
> > -	case BUILT_IN_GOMP_ORDERED_START:
> > -	case BUILT_IN_GOMP_ORDERED_END:
> > -	case BUILT_IN_GOMP_SECTIONS_END:
> > -	case BUILT_IN_GOMP_SECTIONS_END_CANCEL:
> > -	case BUILT_IN_GOMP_SINGLE_COPY_START:
> > -	case BUILT_IN_GOMP_SINGLE_COPY_END:
> > -	  return true;
> > -
> > -	default:
> > -	  /* Fallthru to general call handling.  */;
> > -      }
> > +	}
> > +    }
> >  
> >    /* Check if base is a global static variable that is not read
> >       by the function.  */
> > @@ -2961,7 +3280,9 @@ call_may_clobber_ref_p_1 (gcall *call, ao_ref *ref, bool tbaa_p)
> >  	  modref_summary *summary = get_modref_function_summary (node);
> >  	  if (summary)
> >  	    {
> > -	      if (!modref_may_conflict (call, summary->stores, ref, tbaa_p))
> > +	      if (!modref_may_conflict (call, summary->stores, ref, tbaa_p)
> > +		  && (!summary->writes_errno
> > +		      || !targetm.ref_may_alias_errno (ref)))
> >  		{
> >  		  alias_stats.modref_clobber_no_alias++;
> >  		  if (dump_file && (dump_flags & TDF_DETAILS))
> > @@ -3016,205 +3337,43 @@ call_may_clobber_ref_p_1 (gcall *call, ao_ref *ref, bool tbaa_p)
> >        && SSA_NAME_POINTS_TO_READONLY_MEMORY (TREE_OPERAND (base, 0)))
> >      return false;
> >  
> > +  struct ao_function_info info;
> >    /* 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.  */
> > +     escape points.  */
> >    if (callee != NULL_TREE
> > -      && gimple_call_builtin_p (call, 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_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:
> > -	case BUILT_IN_MEMSET:
> > -	case BUILT_IN_TM_MEMSET:
> > -	CASE_BUILT_IN_TM_STORE (1):
> > -	CASE_BUILT_IN_TM_STORE (2):
> > -	CASE_BUILT_IN_TM_STORE (4):
> > -	CASE_BUILT_IN_TM_STORE (8):
> > -	CASE_BUILT_IN_TM_STORE (FLOAT):
> > -	CASE_BUILT_IN_TM_STORE (DOUBLE):
> > -	CASE_BUILT_IN_TM_STORE (LDOUBLE):
> > -	CASE_BUILT_IN_TM_STORE (M64):
> > -	CASE_BUILT_IN_TM_STORE (M128):
> > -	CASE_BUILT_IN_TM_STORE (M256):
> > -	case BUILT_IN_TM_MEMCPY:
> > -	case BUILT_IN_TM_MEMMOVE:
> > -	  {
> > -	    ao_ref dref;
> > -	    tree size = NULL_TREE;
> > -	    /* Don't pass in size for strncat, as the maximum size
> > -	       is strlen (dest) + n + 1 instead of n, resp.
> > -	       n + 1 at dest + strlen (dest), but strlen (dest) isn't
> > -	       known.  */
> > -	    if (gimple_call_num_args (call) == 3
> > -		&& DECL_FUNCTION_CODE (callee) != BUILT_IN_STRNCAT)
> > -	      size = gimple_call_arg (call, 2);
> > -	    ao_ref_init_from_ptr_and_size (&dref,
> > -					   gimple_call_arg (call, 0),
> > -					   size);
> > -	    return refs_may_alias_p_1 (&dref, ref, false);
> > -	  }
> > -	case BUILT_IN_STRCPY_CHK:
> > -	case BUILT_IN_STRNCPY_CHK:
> > -	case BUILT_IN_MEMCPY_CHK:
> > -	case BUILT_IN_MEMMOVE_CHK:
> > -	case BUILT_IN_MEMPCPY_CHK:
> > -	case BUILT_IN_STPCPY_CHK:
> > -	case BUILT_IN_STPNCPY_CHK:
> > -	case BUILT_IN_STRCAT_CHK:
> > -	case BUILT_IN_STRNCAT_CHK:
> > -	case BUILT_IN_MEMSET_CHK:
> > -	  {
> > -	    ao_ref dref;
> > -	    tree size = NULL_TREE;
> > -	    /* Don't pass in size for __strncat_chk, as the maximum size
> > -	       is strlen (dest) + n + 1 instead of n, resp.
> > -	       n + 1 at dest + strlen (dest), but strlen (dest) isn't
> > -	       known.  */
> > -	    if (gimple_call_num_args (call) == 4
> > -		&& DECL_FUNCTION_CODE (callee) != BUILT_IN_STRNCAT_CHK)
> > -	      size = gimple_call_arg (call, 2);
> > -	    ao_ref_init_from_ptr_and_size (&dref,
> > -					   gimple_call_arg (call, 0),
> > -					   size);
> > -	    return refs_may_alias_p_1 (&dref, ref, false);
> > -	  }
> > -	case BUILT_IN_BCOPY:
> > -	  {
> > -	    ao_ref dref;
> > -	    tree size = gimple_call_arg (call, 2);
> > -	    ao_ref_init_from_ptr_and_size (&dref,
> > -					   gimple_call_arg (call, 1),
> > -					   size);
> > -	    return refs_may_alias_p_1 (&dref, ref, false);
> > -	  }
> > -	/* Allocating memory does not have any side-effects apart from
> > -	   being the definition point for the pointer.  */
> > -	case BUILT_IN_MALLOC:
> > -	case BUILT_IN_ALIGNED_ALLOC:
> > -	case BUILT_IN_CALLOC:
> > -	case BUILT_IN_STRDUP:
> > -	case BUILT_IN_STRNDUP:
> > -	  /* Unix98 specifies that errno is set on allocation failure.  */
> > -	  if (flag_errno_math
> > -	      && targetm.ref_may_alias_errno (ref))
> > -	    return true;
> > -	  return false;
> > -	case BUILT_IN_STACK_SAVE:
> > -	CASE_BUILT_IN_ALLOCA:
> > -	case BUILT_IN_ASSUME_ALIGNED:
> > +      && gimple_call_builtin_p (call, BUILT_IN_NORMAL)
> > +      && (ao_classify_builtin (callee, &info)))
> > +    {
> > +      if (info.flags & AO_FUNCTION_BARRIER)
> > +	return true;
> > +      if ((info.flags & AO_FUNCTION_ERRNO)
> > +	  && flag_errno_math
> > +	  && targetm.ref_may_alias_errno (ref))
> > +	return true;
> > +      if (info.num_param_writes >= 0)
> > +	{
> > +	  for (int i = 0; i < info.num_param_writes; i++)
> > +	    {
> > +	      ao_ref dref;
> > +	      tree size = NULL_TREE;
> > +
> > +	      gcc_checking_assert (info.writes[i].size_param
> > +				   != info.writes[i].param);
> > +	      if (info.writes[i].size_param != -1)
> > +		size = gimple_call_arg (call, info.writes[i].size_param);
> > +	      else if (info.writes[i].size)
> > +		size = build_int_cst (size_type_node, info.writes[i].size);
> > +	      ao_ref_init_from_ptr_and_size (&dref,
> > +					     gimple_call_arg
> > +						 (call,
> > +						  info.writes[i].param),
> > +					     size);
> > +	      if (refs_may_alias_p_1 (&dref, ref, tbaa_p))
> > +		return true;
> > +	    }
> >  	  return false;
> > -	/* But posix_memalign stores a pointer into the memory pointed to
> > -	   by its first argument.  */
> > -	case BUILT_IN_POSIX_MEMALIGN:
> > -	  {
> > -	    tree ptrptr = gimple_call_arg (call, 0);
> > -	    ao_ref dref;
> > -	    ao_ref_init_from_ptr_and_size (&dref, ptrptr,
> > -					   TYPE_SIZE_UNIT (ptr_type_node));
> > -	    return (refs_may_alias_p_1 (&dref, ref, false)
> > -		    || (flag_errno_math
> > -			&& targetm.ref_may_alias_errno (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.  */
> > -	case BUILT_IN_FREE:
> > -	case BUILT_IN_VA_END:
> > -	  {
> > -	    tree ptr = gimple_call_arg (call, 0);
> > -	    return ptr_deref_may_alias_ref_p_1 (ptr, ref);
> > -	  }
> > -	/* Realloc serves both as allocation point and deallocation point.  */
> > -	case BUILT_IN_REALLOC:
> > -	  {
> > -	    tree ptr = gimple_call_arg (call, 0);
> > -	    /* Unix98 specifies that errno is set on allocation failure.  */
> > -	    return ((flag_errno_math
> > -		     && targetm.ref_may_alias_errno (ref))
> > -		    || ptr_deref_may_alias_ref_p_1 (ptr, ref));
> > -	  }
> > -	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:
> > -	  {
> > -	    tree out = gimple_call_arg (call, 1);
> > -	    if (ptr_deref_may_alias_ref_p_1 (out, ref))
> > -	      return true;
> > -	    if (flag_errno_math)
> > -	      break;
> > -	    return false;
> > -	  }
> > -	case BUILT_IN_FREXP:
> > -	case BUILT_IN_FREXPF:
> > -	case BUILT_IN_FREXPL:
> > -	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_1 (out, ref);
> > -	  }
> > -	case BUILT_IN_REMQUO:
> > -	case BUILT_IN_REMQUOF:
> > -	case BUILT_IN_REMQUOL:
> > -	  {
> > -	    tree out = gimple_call_arg (call, 2);
> > -	    if (ptr_deref_may_alias_ref_p_1 (out, ref))
> > -	      return true;
> > -	    if (flag_errno_math)
> > -	      break;
> > -	    return false;
> > -	  }
> > -	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);
> > -	    return (ptr_deref_may_alias_ref_p_1 (sin, ref)
> > -		    || ptr_deref_may_alias_ref_p_1 (cos, ref));
> > -	  }
> > -	/* __sync_* builtins and some OpenMP builtins act as threading
> > -	   barriers.  */
> > -#undef DEF_SYNC_BUILTIN
> > -#define DEF_SYNC_BUILTIN(ENUM, NAME, TYPE, ATTRS) case ENUM:
> > -#include "sync-builtins.def"
> > -#undef DEF_SYNC_BUILTIN
> > -	case BUILT_IN_GOMP_ATOMIC_START:
> > -	case BUILT_IN_GOMP_ATOMIC_END:
> > -	case BUILT_IN_GOMP_BARRIER:
> > -	case BUILT_IN_GOMP_BARRIER_CANCEL:
> > -	case BUILT_IN_GOMP_TASKWAIT:
> > -	case BUILT_IN_GOMP_TASKGROUP_END:
> > -	case BUILT_IN_GOMP_CRITICAL_START:
> > -	case BUILT_IN_GOMP_CRITICAL_END:
> > -	case BUILT_IN_GOMP_CRITICAL_NAME_START:
> > -	case BUILT_IN_GOMP_CRITICAL_NAME_END:
> > -	case BUILT_IN_GOMP_LOOP_END:
> > -	case BUILT_IN_GOMP_LOOP_END_CANCEL:
> > -	case BUILT_IN_GOMP_ORDERED_START:
> > -	case BUILT_IN_GOMP_ORDERED_END:
> > -	case BUILT_IN_GOMP_SECTIONS_END:
> > -	case BUILT_IN_GOMP_SECTIONS_END_CANCEL:
> > -	case BUILT_IN_GOMP_SINGLE_COPY_START:
> > -	case BUILT_IN_GOMP_SINGLE_COPY_END:
> > -	  return true;
> > -	default:
> > -	  /* Fallthru to general call handling.  */;
> > -      }
> > +	}
> > +    }
> >  
> >    /* Check if base is a global static variable that is not written
> >       by the function.  */
> > 
> 
> -- 
> Richard Biener <rguenther@suse.de>
> SUSE Software Solutions Germany GmbH, Maxfeldstrasse 5, 90409 Nuernberg,
> Germany; GF: Felix Imend
Richard Biener Sept. 28, 2020, 9:53 a.m. UTC | #3
On Mon, 28 Sep 2020, Jan Hubicka wrote:

> > On Mon, 28 Sep 2020, Jan Hubicka wrote:
> > 
> > > Hi,
> > > ipa-reference, ipa-pure-const and ipa-modref could use the knowledge
> > > about bulitins which is currently harwired into
> > > ref_maybe_used_by_call_p_1, call_may_clobber_ref_p_1 and the PTA
> > > computation.  This patch breaks out logic implemented in the first two
> > > into a form of a simple descriptor that can be used by the IPA passes
> > > (and other code).
> > > 
> > > I was considering an option of putting this into def file but I do not think
> > > it is feasible without cluttering it quite a lot.
> > > 
> > > For ipa-modref I implemented dump informing about missing builtins. strlen,
> > > sqrt and exp seems common offenders, but that can be handled incrementally
> > > if the approach looks reasonable.
> > > I would also look adding the description for PTA (perhaps with some
> > > special cases remainig since it is more ad-hoc)
> > > 
> > > Bootstrapped/regtested x86_64-linux, OK?
> > 
> > Hmm, this looks awfully similar to fn-spec handling done in
> > process_args via gimple_call_arg_flags ()?
> 
> Kind of similar (I was also looking into this, since with modref we
> could detect noescape attribute rather easily).
> 
> I am not quite sure the attribute machinery overlaps that well with what
> we do with builtins.  tree-ssa-alias only use gimple_call_arg_flags to
> detect that pure/const fuction does not use its argument.

Hmm, no - it expects the gimple_call_use/clobber_set to include
actions of the called function itself (const functions none here)
but for passed-by-value the loads may be in the call itself
which is where it uses gimple_call_arg_flags to skip unused ones.

But note that PTA uses gimple_call_arg_flags to compute
the gimple_call_use/clobber_set (but only in IPA mode) and the individual 
BUILT_IN_* handlings in tree-ssa-alias.c do what PTA would do
here, just directly as alias queries.  Originally I tried adding
"fn spec"s to BUILT_IN_* decls but that got out-of-hands ...

For example

        /* All the following functions read memory pointed to by
           their second argument.  strcat/strncat additionally
           reads memory pointed to by the first argument.  */
        case BUILT_IN_STRCAT:
        case BUILT_IN_STRNCAT:
          {
            ao_ref dref;
            ao_ref_init_from_ptr_and_size (&dref,
                                           gimple_call_arg (call, 0),
                                           NULL_TREE);
            if (refs_may_alias_p_1 (&dref, ref, false))
              return true;
          }

would be covered by "1WR" (W also implies read).  So the question
would be whether at least parts of your patch could be implemented
by making gimple_call_fnspec () return pre-determined fn-specs
for BUILT_IN_* (like we do with internal_fn_fnspec).

>  We would need
> to invent how to add info that non pure/const function only access the
> argument according to fn spec, add way to represent sizes of accesses
> and how to handle errno.

True - fn-spec lacks an ability to specify access size - fortunately
it's internal and we could change it ;)  Whether or not sth can clobber
errno is sth we eventually need to move to the stmt level anyway
(-f[no-]math-errno crossing inline boundary) - bit sad to waste a
bit in a gimple call for this though.  OTOH we waste a ton of space
in the call_used/call_clobbered members due to bad packing
(unsigned int bitfield followed by a pointer to a bitmap).  Eventually
we could offload this kind of info from the main stmt.  We could
also allocate a fake UID to represent errno (but then the rest of
the bits in call_used/call_clobbered have to be precise) - but note
call_used/call_clobbered does not transfer during inlining.

So for the access size issue we could blow up fnspec by factor of two,
reserving two chars per argument/return value and do

 1.W3R.

for strncat plus add gimple_call_arg_size to access it.  The 2nd
slot in return value could host the errno thing (eh).

 .e

for sqrt for example.

Just to repeat again - the info looks too similar to warrant an
extra mechanism to record it.

Richard.

> Honza
> > 
> > > gcc/ChangeLog:
> > > 
> > > 2020-09-28  Jan Hubicka  <hubicka@ucw.cz>
> > > 
> > > 	* tree-ssa-alias.c (ao_classify_builtin): New function commonizing
> > > 	logic from ...
> > > 	(ref_maybe_used_by_call_p_1): ... here.
> > > 	(call_may_clobber_ref_p_1): ... and here.
> > > 	* tree-ssa-alias.h (enum ao_function_flags): New enum.
> > > 	(struct ao_function_info): New structure.
> > > 	(ao_classify_builtin): Declare.
> > > 
> > > diff --git a/gcc/tree-ssa-alias.h b/gcc/tree-ssa-alias.h
> > > index 1dd02c0ea62..eecb8da6dd7 100644
> > > --- a/gcc/tree-ssa-alias.h
> > > +++ b/gcc/tree-ssa-alias.h
> > > @@ -108,6 +108,33 @@ ao_ref::max_size_known_p () const
> > >    return known_size_p (max_size);
> > >  }
> > >  
> > > +/* Flags used in ao_function_info.  */
> > > +
> > > +enum ao_function_flags
> > > +{
> > > +  AO_FUNCTION_BARRIER = 1,
> > > +  AO_FUNCTION_ERRNO = 2,
> > > +};
> > > +
> > > +/* Describe side effects relevant for alias analysis of function call to
> > > +   DECL.  */
> > > +
> > > +struct ao_function_info
> > > +{
> > > +  int num_param_reads;  /* Number of parameters function reads from,
> > > +			   -1 if reads are unknown.  */
> > > +  struct ao_access_info
> > > +    {
> > > +      char param; 	/* Index of parameter read/written from.  */
> > > +      char size_param;	/* Index of parameter specifying size of the access,
> > > +			   -1 if unknown.  */
> > > +      char size;	/* Size of access if known, 0 if unknown.  */
> > > +    } reads[2];
> > > +  int num_param_writes;
> > > +  struct ao_access_info writes[2];
> > > +  enum ao_function_flags flags;
> > > +};
> > > +
> > >  /* In tree-ssa-alias.c  */
> > >  extern void ao_ref_init (ao_ref *, tree);
> > >  extern void ao_ref_init_from_ptr_and_size (ao_ref *, tree, tree);
> > > @@ -158,6 +185,7 @@ extern void debug (pt_solution *ptr);
> > >  extern void dump_points_to_info_for (FILE *, tree);
> > >  extern void debug_points_to_info_for (tree);
> > >  extern void dump_alias_stats (FILE *);
> > > +extern bool ao_classify_builtin (tree callee, ao_function_info *info);
> > >  
> > >  
> > >  /* In tree-ssa-structalias.c  */
> > > diff --git a/gcc/tree-ssa-alias.c b/gcc/tree-ssa-alias.c
> > > index fe390d4ffbe..c182e7bb39c 100644
> > > --- a/gcc/tree-ssa-alias.c
> > > +++ b/gcc/tree-ssa-alias.c
> > > @@ -2503,6 +2503,507 @@ modref_may_conflict (const gimple *stmt,
> > >    return false;
> > >  }
> > >  
> > > +/* If CALLEE has known side effects, fill in INFO and return true.
> > > +   See tree-ssa-structalias.c:find_func_aliases
> > > +   for the list of builtins we might need to handle here.  */
> > > +
> > > +bool
> > > +ao_classify_builtin (tree callee, ao_function_info *info)
> > > +{
> > > +  built_in_function code = DECL_FUNCTION_CODE (callee);
> > > +
> > > +  switch (code)
> > > +    {
> > > +      /* All the following functions read memory pointed to by
> > > +	 their second argument and write memory pointed to by first
> > > +	 argument.
> > > +	 strcat/strncat additionally reads memory pointed to by the first
> > > +	 argument.  */
> > > +      case BUILT_IN_STRCAT:
> > > +	{
> > > +	  const static struct ao_function_info ret_info
> > > +	       = {
> > > +		    2,				/* num_param_reads.  */
> > > +
> > > +		    /* Reads and write descriptors are triples containing:
> > > +		       - index of parameter read
> > > +		       - index of parameter specifying access size
> > > +			 (-1 if unknown)
> > > +		       - access size in bytes (0 if unkown).  */
> > > +
> > > +		    {{0, -1, 0}, {1, -1, 0}},	/* Param read.  */
> > > +		    1,				/* num_param_writes.  */
> > > +		    {{0, -1, 0}},		/* Param written.  */
> > > +		    (ao_function_flags)0,	/* flags.  */
> > > +		 };
> > > +	  *info = ret_info;
> > > +	  return true;
> > > +	}
> > > +      case BUILT_IN_STRNCAT:
> > > +	{
> > > +	  const static struct ao_function_info ret_info
> > > +	       = {
> > > +		    2,				/* num_param_reads.  */
> > > +		    {{0, -1, 0}, {1, 2, 0}},	/* Param read.  */
> > > +		    1,				/* num_param_writes.  */
> > > +		    {{0, -1, 0}},		/* Param written.  */
> > > +		    (ao_function_flags)0,	/* flags.  */
> > > +		 };
> > > +	  *info = ret_info;
> > > +	  return true;
> > > +	}
> > > +      case BUILT_IN_STRCPY:
> > > +      case BUILT_IN_STPCPY:
> > > +	{
> > > +	  const static struct ao_function_info ret_info
> > > +	       = {
> > > +		    1,				/* num_param_reads.  */
> > > +		    {{1, -1, 0}},		/* Param read.  */
> > > +		    1,				/* num_param_writes.  */
> > > +		    {{0, -1, 0}},		/* Param written.  */
> > > +		    (ao_function_flags)0,	/* flags.  */
> > > +		 };
> > > +	  *info = ret_info;
> > > +	  return true;
> > > +	}
> > > +      case BUILT_IN_STRNCPY:
> > > +      case BUILT_IN_MEMCPY:
> > > +      case BUILT_IN_MEMMOVE:
> > > +      case BUILT_IN_MEMPCPY:
> > > +      case BUILT_IN_STPNCPY:
> > > +      case BUILT_IN_TM_MEMCPY:
> > > +      case BUILT_IN_TM_MEMMOVE:
> > > +	{
> > > +	  const static struct ao_function_info ret_info
> > > +	       = {
> > > +		    1,				/* num_param_reads.  */
> > > +		    {{1, 2, 0}},		/* Param read.  */
> > > +		    1,				/* num_param_writes.  */
> > > +		    {{0, 2, 0}},		/* Param written.  */
> > > +		    (ao_function_flags)0,	/* flags.  */
> > > +		 };
> > > +	  *info = ret_info;
> > > +	  return true;
> > > +	}
> > > +      case BUILT_IN_STRCAT_CHK:
> > > +	{
> > > +	  const static struct ao_function_info ret_info
> > > +	       = {
> > > +		    2,				/* num_param_reads.  */
> > > +		    {{0, -1, 0}, {1, -1, 0}},	/* Param read.  */
> > > +		    1,				/* num_param_writes.  */
> > > +		    {{0, -1, 0}},		/* Param written.  */
> > > +		    (ao_function_flags)0,	/* flags.  */
> > > +		 };
> > > +	  *info = ret_info;
> > > +	  return true;
> > > +	}
> > > +      case BUILT_IN_STRNCAT_CHK:
> > > +	{
> > > +	  const static struct ao_function_info ret_info
> > > +	       = {
> > > +		    2,				/* num_param_reads.  */
> > > +		    {{0, -1, 0}, {1, 2, 0}},	/* Param read.  */
> > > +		    1,				/* num_param_writes.  */
> > > +		    {{0, -1, 0}},		/* Param written.  */
> > > +		    (ao_function_flags)0,	/* flags.  */
> > > +		 };
> > > +	  *info = ret_info;
> > > +	  return true;
> > > +	}
> > > +      case BUILT_IN_STRCPY_CHK:
> > > +      case BUILT_IN_STPCPY_CHK:
> > > +	{
> > > +	  const static struct ao_function_info ret_info
> > > +	       = {
> > > +		    1,				/* num_param_reads.  */
> > > +		    {{1, -1, 0}},		/* Param read.  */
> > > +		    1,				/* num_param_writes.  */
> > > +		    {{0, -1, 0}},		/* Param written.  */
> > > +		    (ao_function_flags)0,	/* flags.  */
> > > +		 };
> > > +	  *info = ret_info;
> > > +	  return true;
> > > +	}
> > > +      case BUILT_IN_STRNCPY_CHK:
> > > +      case BUILT_IN_MEMCPY_CHK:
> > > +      case BUILT_IN_MEMMOVE_CHK:
> > > +      case BUILT_IN_MEMPCPY_CHK:
> > > +      case BUILT_IN_STPNCPY_CHK:
> > > +	{
> > > +	  const static struct ao_function_info ret_info
> > > +	       = {
> > > +		    1,				/* num_param_reads.  */
> > > +		    {{1, 2, 0}},		/* Param read.  */
> > > +		    1,				/* num_param_writes.  */
> > > +		    {{0, 2, 0}},		/* Param written.  */
> > > +		    (ao_function_flags)0,	/* flags.  */
> > > +		 };
> > > +	  *info = ret_info;
> > > +	  return true;
> > > +	}
> > > +      case BUILT_IN_BCOPY:
> > > +	{
> > > +	  const static struct ao_function_info ret_info
> > > +	       = {
> > > +		    1,				/* num_param_reads.  */
> > > +		    {{0, 2, 0}},		/* Param read.  */
> > > +		    1,				/* num_param_writes.  */
> > > +		    {{1, 2, 0}},		/* Param written.  */
> > > +		    (ao_function_flags)0,	/* flags.  */
> > > +		 };
> > > +	  *info = ret_info;
> > > +	  return true;
> > > +	}
> > > +
> > > +      /* The following functions read memory pointed to by their
> > > +	 first argument.  */
> > > +      CASE_BUILT_IN_TM_LOAD (1):
> > > +      CASE_BUILT_IN_TM_LOAD (2):
> > > +      CASE_BUILT_IN_TM_LOAD (4):
> > > +      CASE_BUILT_IN_TM_LOAD (8):
> > > +      CASE_BUILT_IN_TM_LOAD (FLOAT):
> > > +      CASE_BUILT_IN_TM_LOAD (DOUBLE):
> > > +      CASE_BUILT_IN_TM_LOAD (LDOUBLE):
> > > +      CASE_BUILT_IN_TM_LOAD (M64):
> > > +      CASE_BUILT_IN_TM_LOAD (M128):
> > > +      CASE_BUILT_IN_TM_LOAD (M256):
> > > +      case BUILT_IN_TM_LOG:
> > > +      case BUILT_IN_TM_LOG_1:
> > > +      case BUILT_IN_TM_LOG_2:
> > > +      case BUILT_IN_TM_LOG_4:
> > > +      case BUILT_IN_TM_LOG_8:
> > > +      case BUILT_IN_TM_LOG_FLOAT:
> > > +      case BUILT_IN_TM_LOG_DOUBLE:
> > > +      case BUILT_IN_TM_LOG_LDOUBLE:
> > > +      case BUILT_IN_TM_LOG_M64:
> > > +      case BUILT_IN_TM_LOG_M128:
> > > +      case BUILT_IN_TM_LOG_M256:
> > > +
> > > +      case BUILT_IN_INDEX:
> > > +      case BUILT_IN_STRCHR:
> > > +      case BUILT_IN_STRRCHR:
> > > +	{
> > > +	  const static struct ao_function_info ret_info
> > > +	       = {
> > > +		    1,				/* num_param_reads.  */
> > > +		    /* TODO: For TM builtins size is known.  */
> > > +		    {{0, -1, 0}},		/* Param read.  */
> > > +		    0,				/* num_param_writes.  */
> > > +		    {},				/* Param written.  */
> > > +		    (ao_function_flags)0,	/* flags.  */
> > > +		 };
> > > +	  *info = ret_info;
> > > +	  return true;
> > > +	}
> > > +
> > > +      /* These read memory pointed to by the first argument.
> > > +	 Allocating memory does not have any side-effects apart from
> > > +	 being the definition point for the pointer.
> > > +	 Unix98 specifies that errno is set on allocation failure.  */
> > > +      case BUILT_IN_STRDUP:
> > > +	{
> > > +	  const static struct ao_function_info ret_info
> > > +	       = {
> > > +		    1,				/* num_param_reads.  */
> > > +		    {{0, -1, 0}},		/* Param read.  */
> > > +		    0,				/* num_param_writes.  */
> > > +		    {},				/* Param written.  */
> > > +		    AO_FUNCTION_ERRNO,		/* flags.  */
> > > +		 };
> > > +	  *info = ret_info;
> > > +	  return true;
> > > +	}
> > > +      case BUILT_IN_STRNDUP:
> > > +	{
> > > +	  const static struct ao_function_info ret_info
> > > +	       = {
> > > +		    1,				/* num_param_reads.  */
> > > +		    {{0, 1, 0}},		/* Param read.  */
> > > +		    0,				/* num_param_writes.  */
> > > +		    {},				/* Param written.  */
> > > +		    AO_FUNCTION_ERRNO,		/* flags.  */
> > > +		 };
> > > +	  *info = ret_info;
> > > +	  return true;
> > > +	}
> > > +      /* Allocating memory does not have any side-effects apart from
> > > +	 being the definition point for the pointer.  */
> > > +      case BUILT_IN_MALLOC:
> > > +      case BUILT_IN_ALIGNED_ALLOC:
> > > +      case BUILT_IN_CALLOC:
> > > +	{
> > > +	  const static struct ao_function_info ret_info
> > > +	       = {
> > > +		    0,				/* num_param_reads.  */
> > > +		    {},				/* Param read.  */
> > > +		    0,				/* num_param_writes.  */
> > > +		    {},				/* Param written.  */
> > > +		    AO_FUNCTION_ERRNO,		/* flags.  */
> > > +		 };
> > > +	  *info = ret_info;
> > > +	  return true;
> > > +	}
> > > +      /* These read memory pointed to by the first argument with size
> > > +	 in the third argument.  */
> > > +      case BUILT_IN_MEMCHR:
> > > +	{
> > > +	  const static struct ao_function_info ret_info
> > > +	       = {
> > > +		    1,				/* num_param_reads.  */
> > > +		    {{0, 2, 0}},		/* Param read.  */
> > > +		    0,				/* num_param_writes.  */
> > > +		    {},				/* Param written.  */
> > > +		    (ao_function_flags)0,	/* flags.  */
> > > +		 };
> > > +	  *info = ret_info;
> > > +	  return true;
> > > +	}
> > > +      /* These read memory pointed to by the first and second arguments.  */
> > > +      case BUILT_IN_STRSTR:
> > > +      case BUILT_IN_STRPBRK:
> > > +	{
> > > +	  static struct ao_function_info ret_info
> > > +	       = {
> > > +		    2,				/* num_param_reads.  */
> > > +		    {{0, -1, 0}, {1, -1, 0}},	/* Param read.  */
> > > +		    0,				/* num_param_writes.  */
> > > +		    {},				/* Param written.  */
> > > +		    (ao_function_flags)0,	/* flags.  */
> > > +		 };
> > > +	  *info = ret_info;
> > > +	  return true;
> > > +	}
> > > +      /* Freeing memory kills the pointed-to memory.  More importantly
> > > +	 the call has to serve as a barrier for moving loads and stores
> > > +	 across it.  */
> > > +      case BUILT_IN_FREE:
> > > +      case BUILT_IN_VA_END:
> > > +	{
> > > +	  const static struct ao_function_info ret_info
> > > +	       = {
> > > +		    0,				/* num_param_reads.  */
> > > +		    {},				/* Param read.  */
> > > +		    1,				/* num_param_writes.  */
> > > +		    {{0, -1, 0}},		/* Param written.  */
> > > +		    (ao_function_flags)0,	/* flags.  */
> > > +		 };
> > > +	  *info = ret_info;
> > > +	  return true;
> > > +	}
> > > +      /* Realloc serves both as allocation point and deallocation point.  */
> > > +      case BUILT_IN_REALLOC:
> > > +	{
> > > +	  const static struct ao_function_info ret_info
> > > +	       = {
> > > +		    1,				/* num_param_reads.  */
> > > +		    {{0, 1, 0}},		/* Param read.  */
> > > +		    0,				/* num_param_writes.  */
> > > +		    {{0, -1, 0}},		/* Param written.  */
> > > +		    AO_FUNCTION_ERRNO,		/* flags.  */
> > > +		 };
> > > +	  *info = ret_info;
> > > +	  return true;
> > > +	}
> > > +      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:
> > > +	{
> > > +	  const static struct ao_function_info ret_info
> > > +	       = {
> > > +		    0,				/* num_param_reads.  */
> > > +		    {},				/* Param read.  */
> > > +		    1,				/* num_param_writes.  */
> > > +		    {{1, -1, 0}},		/* Param written.  */
> > > +		    AO_FUNCTION_ERRNO,		/* flags.  */
> > > +		 };
> > > +	  *info = ret_info;
> > > +	  return true;
> > > +	}
> > > +      case BUILT_IN_FREXP:
> > > +      case BUILT_IN_FREXPF:
> > > +      case BUILT_IN_FREXPL:
> > > +      case BUILT_IN_MODF:
> > > +      case BUILT_IN_MODFF:
> > > +      case BUILT_IN_MODFL:
> > > +	{
> > > +	  const static struct ao_function_info ret_info
> > > +	       = {
> > > +		    0,				/* num_param_reads.  */
> > > +		    {},				/* Param read.  */
> > > +		    1,				/* num_param_writes.  */
> > > +		    {{1, -1, 0}},		/* Param written.  */
> > > +		    (ao_function_flags)0,	/* flags.  */
> > > +		 };
> > > +	  *info = ret_info;
> > > +	  return true;
> > > +	}
> > > +      case BUILT_IN_REMQUO:
> > > +      case BUILT_IN_REMQUOF:
> > > +      case BUILT_IN_REMQUOL:
> > > +	{
> > > +	  const static struct ao_function_info ret_info
> > > +	       = {
> > > +		    0,				/* num_param_reads.  */
> > > +		    {},				/* Param read.  */
> > > +		    1,				/* num_param_writes.  */
> > > +		    {{2, -1, 0}},		/* Param written.  */
> > > +		    (ao_function_flags)0,	/* flags.  */
> > > +		 };
> > > +	  *info = ret_info;
> > > +	  return true;
> > > +	}
> > > +      case BUILT_IN_SINCOS:
> > > +      case BUILT_IN_SINCOSF:
> > > +      case BUILT_IN_SINCOSL:
> > > +	{
> > > +	  static struct ao_function_info ret_info
> > > +	       = {
> > > +		    0,				/* num_param_reads.  */
> > > +		    {},				/* Param read.  */
> > > +		    1,				/* num_param_writes.  */
> > > +		    {{1, -1, 0}, {2, -1, 0}},	/* Param written.  */
> > > +		    (ao_function_flags)0,	/* flags.  */
> > > +		 };
> > > +	  tree type = float_ptr_type_node;
> > > +	  if (code == BUILT_IN_SINCOS)
> > > +	    type = double_ptr_type_node;
> > > +	  else
> > > +	    type = long_double_ptr_type_node;
> > > +	  ret_info.writes[0].size = ret_info.writes[1].size
> > > +		 = tree_to_uhwi (TYPE_SIZE_UNIT (type));
> > > +	  *info = ret_info;
> > > +	  return true;
> > > +	}
> > > +      case BUILT_IN_MEMSET:
> > > +      case BUILT_IN_MEMSET_CHK:
> > > +      case BUILT_IN_TM_MEMSET:
> > > +	{
> > > +	  const static struct ao_function_info ret_info
> > > +	       = {
> > > +		    0,				/* num_param_reads.  */
> > > +		    {},				/* Param read.  */
> > > +		    1,				/* num_param_writes.  */
> > > +		    {0, 2, 0},			/* Param written.  */
> > > +		    (ao_function_flags)0,	/* flags.  */
> > > +		 };
> > > +	  *info = ret_info;
> > > +	  return true;
> > > +	}
> > > +      CASE_BUILT_IN_TM_STORE (1):
> > > +      CASE_BUILT_IN_TM_STORE (2):
> > > +      CASE_BUILT_IN_TM_STORE (4):
> > > +      CASE_BUILT_IN_TM_STORE (8):
> > > +      CASE_BUILT_IN_TM_STORE (FLOAT):
> > > +      CASE_BUILT_IN_TM_STORE (DOUBLE):
> > > +      CASE_BUILT_IN_TM_STORE (LDOUBLE):
> > > +      CASE_BUILT_IN_TM_STORE (M64):
> > > +      CASE_BUILT_IN_TM_STORE (M128):
> > > +      CASE_BUILT_IN_TM_STORE (M256):
> > > +	{
> > > +	  const static struct ao_function_info ret_info
> > > +	       = {
> > > +		    0,				/* num_param_reads.  */
> > > +		    {},				/* Param read.  */
> > > +		    1,				/* num_param_writes.  */
> > > +		    /* TODO: Size is known.  */
> > > +		    {0, -1, 0},			/* Param written.  */
> > > +		    (ao_function_flags)0,	/* flags.  */
> > > +		 };
> > > +	  *info = ret_info;
> > > +	  return true;
> > > +	}
> > > +      case BUILT_IN_STACK_SAVE:
> > > +      CASE_BUILT_IN_ALLOCA:
> > > +      case BUILT_IN_ASSUME_ALIGNED:
> > > +	{
> > > +	  const static struct ao_function_info ret_info
> > > +	       = {
> > > +		    0,				/* num_param_reads.  */
> > > +		    {},				/* Param read.  */
> > > +		    0,				/* num_param_writes.  */
> > > +		    {},				/* Param written.  */
> > > +		    (ao_function_flags)0,	/* flags.  */
> > > +		 };
> > > +	  *info = ret_info;
> > > +	  return true;
> > > +	}
> > > +      /* But posix_memalign stores a pointer into the memory pointed to
> > > +	 by its first argument.  */
> > > +      case BUILT_IN_POSIX_MEMALIGN:
> > > +	{
> > > +	  static struct ao_function_info ret_info
> > > +	       = {
> > > +		    0,				/* num_param_reads.  */
> > > +		    {},				/* Param read.  */
> > > +		    0,				/* num_param_writes.  */
> > > +		    {{0, -1, 0}},		/* Param written.  */
> > > +		    AO_FUNCTION_ERRNO,		/* flags.  */
> > > +		 };
> > > +	  ret_info.writes[0].size
> > > +		 = tree_to_uhwi (TYPE_SIZE_UNIT (ptr_type_node));
> > > +	  *info = ret_info;
> > > +	  return true;
> > > +	}
> > > +      /* The following builtins do not read from memory.  */
> > > +      case BUILT_IN_STACK_RESTORE:
> > > +	{
> > > +	  const static struct ao_function_info ret_info
> > > +	       = {
> > > +		    0,				/* num_param_reads.  */
> > > +		    {},				/* Param read.  */
> > > +		    0,				/* num_param_writes.  */
> > > +		    {},				/* Param written.  */
> > > +		    (ao_function_flags)0,	/* flags.  */
> > > +		 };
> > > +	  *info = ret_info;
> > > +	  return true;
> > > +	}
> > > +      /* __sync_* builtins and some OpenMP builtins act as threading
> > > +	 barriers.  */
> > > +#undef DEF_SYNC_BUILTIN
> > > +#define DEF_SYNC_BUILTIN(ENUM, NAME, TYPE, ATTRS) case ENUM:
> > > +#include "sync-builtins.def"
> > > +#undef DEF_SYNC_BUILTIN
> > > +      case BUILT_IN_GOMP_ATOMIC_START:
> > > +      case BUILT_IN_GOMP_ATOMIC_END:
> > > +      case BUILT_IN_GOMP_BARRIER:
> > > +      case BUILT_IN_GOMP_BARRIER_CANCEL:
> > > +      case BUILT_IN_GOMP_TASKWAIT:
> > > +      case BUILT_IN_GOMP_TASKGROUP_END:
> > > +      case BUILT_IN_GOMP_CRITICAL_START:
> > > +      case BUILT_IN_GOMP_CRITICAL_END:
> > > +      case BUILT_IN_GOMP_CRITICAL_NAME_START:
> > > +      case BUILT_IN_GOMP_CRITICAL_NAME_END:
> > > +      case BUILT_IN_GOMP_LOOP_END:
> > > +      case BUILT_IN_GOMP_LOOP_END_CANCEL:
> > > +      case BUILT_IN_GOMP_ORDERED_START:
> > > +      case BUILT_IN_GOMP_ORDERED_END:
> > > +      case BUILT_IN_GOMP_SECTIONS_END:
> > > +      case BUILT_IN_GOMP_SECTIONS_END_CANCEL:
> > > +      case BUILT_IN_GOMP_SINGLE_COPY_START:
> > > +      case BUILT_IN_GOMP_SINGLE_COPY_END:
> > > +	{
> > > +	  const static struct ao_function_info ret_info
> > > +	       = {
> > > +		    -1,				/* num_param_reads.  */
> > > +		    {},				/* Param read.  */
> > > +		    -1,				/* num_param_writes.  */
> > > +		    {},				/* Param written.  */
> > > +		    AO_FUNCTION_BARRIER,	/* flags.  */
> > > +		 };
> > > +	  *info = ret_info;
> > > +	  return true;
> > > +	}
> > > +
> > > +      default:
> > > +	return false;
> > > +    }
> > > +}
> > > +
> > >  /* If the call CALL may use the memory reference REF return true,
> > >     otherwise return false.  */
> > >  
> > > @@ -2574,219 +3075,37 @@ ref_maybe_used_by_call_p_1 (gcall *call, ao_ref *ref, bool tbaa_p)
> > >    /* 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.  */
> > > +  struct ao_function_info info;
> > >    if (callee != NULL_TREE
> > > -      && gimple_call_builtin_p (call, BUILT_IN_NORMAL))
> > > -    switch (DECL_FUNCTION_CODE (callee))
> > > -      {
> > > -	/* All the following functions read memory pointed to by
> > > -	   their second argument.  strcat/strncat additionally
> > > -	   reads memory pointed to by the first argument.  */
> > > -	case BUILT_IN_STRCAT:
> > > -	case BUILT_IN_STRNCAT:
> > > -	  {
> > > -	    ao_ref dref;
> > > -	    ao_ref_init_from_ptr_and_size (&dref,
> > > -					   gimple_call_arg (call, 0),
> > > -					   NULL_TREE);
> > > -	    if (refs_may_alias_p_1 (&dref, ref, false))
> > > -	      return true;
> > > -	  }
> > > -	  /* FALLTHRU */
> > > -	case BUILT_IN_STRCPY:
> > > -	case BUILT_IN_STRNCPY:
> > > -	case BUILT_IN_MEMCPY:
> > > -	case BUILT_IN_MEMMOVE:
> > > -	case BUILT_IN_MEMPCPY:
> > > -	case BUILT_IN_STPCPY:
> > > -	case BUILT_IN_STPNCPY:
> > > -	case BUILT_IN_TM_MEMCPY:
> > > -	case BUILT_IN_TM_MEMMOVE:
> > > -	  {
> > > -	    ao_ref dref;
> > > -	    tree size = NULL_TREE;
> > > -	    if (gimple_call_num_args (call) == 3)
> > > -	      size = gimple_call_arg (call, 2);
> > > -	    ao_ref_init_from_ptr_and_size (&dref,
> > > -					   gimple_call_arg (call, 1),
> > > -					   size);
> > > -	    return refs_may_alias_p_1 (&dref, ref, false);
> > > -	  }
> > > -	case BUILT_IN_STRCAT_CHK:
> > > -	case BUILT_IN_STRNCAT_CHK:
> > > -	  {
> > > -	    ao_ref dref;
> > > -	    ao_ref_init_from_ptr_and_size (&dref,
> > > -					   gimple_call_arg (call, 0),
> > > -					   NULL_TREE);
> > > -	    if (refs_may_alias_p_1 (&dref, ref, false))
> > > -	      return true;
> > > -	  }
> > > -	  /* FALLTHRU */
> > > -	case BUILT_IN_STRCPY_CHK:
> > > -	case BUILT_IN_STRNCPY_CHK:
> > > -	case BUILT_IN_MEMCPY_CHK:
> > > -	case BUILT_IN_MEMMOVE_CHK:
> > > -	case BUILT_IN_MEMPCPY_CHK:
> > > -	case BUILT_IN_STPCPY_CHK:
> > > -	case BUILT_IN_STPNCPY_CHK:
> > > -	  {
> > > -	    ao_ref dref;
> > > -	    tree size = NULL_TREE;
> > > -	    if (gimple_call_num_args (call) == 4)
> > > -	      size = gimple_call_arg (call, 2);
> > > -	    ao_ref_init_from_ptr_and_size (&dref,
> > > -					   gimple_call_arg (call, 1),
> > > -					   size);
> > > -	    return refs_may_alias_p_1 (&dref, ref, false);
> > > -	  }
> > > -	case BUILT_IN_BCOPY:
> > > -	  {
> > > -	    ao_ref dref;
> > > -	    tree size = gimple_call_arg (call, 2);
> > > -	    ao_ref_init_from_ptr_and_size (&dref,
> > > -					   gimple_call_arg (call, 0),
> > > -					   size);
> > > -	    return refs_may_alias_p_1 (&dref, ref, false);
> > > -	  }
> > > -
> > > -	/* The following functions read memory pointed to by their
> > > -	   first argument.  */
> > > -	CASE_BUILT_IN_TM_LOAD (1):
> > > -	CASE_BUILT_IN_TM_LOAD (2):
> > > -	CASE_BUILT_IN_TM_LOAD (4):
> > > -	CASE_BUILT_IN_TM_LOAD (8):
> > > -	CASE_BUILT_IN_TM_LOAD (FLOAT):
> > > -	CASE_BUILT_IN_TM_LOAD (DOUBLE):
> > > -	CASE_BUILT_IN_TM_LOAD (LDOUBLE):
> > > -	CASE_BUILT_IN_TM_LOAD (M64):
> > > -	CASE_BUILT_IN_TM_LOAD (M128):
> > > -	CASE_BUILT_IN_TM_LOAD (M256):
> > > -	case BUILT_IN_TM_LOG:
> > > -	case BUILT_IN_TM_LOG_1:
> > > -	case BUILT_IN_TM_LOG_2:
> > > -	case BUILT_IN_TM_LOG_4:
> > > -	case BUILT_IN_TM_LOG_8:
> > > -	case BUILT_IN_TM_LOG_FLOAT:
> > > -	case BUILT_IN_TM_LOG_DOUBLE:
> > > -	case BUILT_IN_TM_LOG_LDOUBLE:
> > > -	case BUILT_IN_TM_LOG_M64:
> > > -	case BUILT_IN_TM_LOG_M128:
> > > -	case BUILT_IN_TM_LOG_M256:
> > > -	  return ptr_deref_may_alias_ref_p_1 (gimple_call_arg (call, 0), ref);
> > > -
> > > -	/* These read memory pointed to by the first argument.  */
> > > -	case BUILT_IN_STRDUP:
> > > -	case BUILT_IN_STRNDUP:
> > > -	case BUILT_IN_REALLOC:
> > > -	  {
> > > -	    ao_ref dref;
> > > -	    tree size = NULL_TREE;
> > > -	    if (gimple_call_num_args (call) == 2)
> > > -	      size = gimple_call_arg (call, 1);
> > > -	    ao_ref_init_from_ptr_and_size (&dref,
> > > -					   gimple_call_arg (call, 0),
> > > -					   size);
> > > -	    return refs_may_alias_p_1 (&dref, ref, false);
> > > -	  }
> > > -	/* These read memory pointed to by the first argument.  */
> > > -	case BUILT_IN_INDEX:
> > > -	case BUILT_IN_STRCHR:
> > > -	case BUILT_IN_STRRCHR:
> > > -	  {
> > > -	    ao_ref dref;
> > > -	    ao_ref_init_from_ptr_and_size (&dref,
> > > -					   gimple_call_arg (call, 0),
> > > -					   NULL_TREE);
> > > -	    return refs_may_alias_p_1 (&dref, ref, false);
> > > -	  }
> > > -	/* These read memory pointed to by the first argument with size
> > > -	   in the third argument.  */
> > > -	case BUILT_IN_MEMCHR:
> > > -	  {
> > > -	    ao_ref dref;
> > > -	    ao_ref_init_from_ptr_and_size (&dref,
> > > -					   gimple_call_arg (call, 0),
> > > -					   gimple_call_arg (call, 2));
> > > -	    return refs_may_alias_p_1 (&dref, ref, false);
> > > -	  }
> > > -	/* These read memory pointed to by the first and second arguments.  */
> > > -	case BUILT_IN_STRSTR:
> > > -	case BUILT_IN_STRPBRK:
> > > -	  {
> > > -	    ao_ref dref;
> > > -	    ao_ref_init_from_ptr_and_size (&dref,
> > > -					   gimple_call_arg (call, 0),
> > > -					   NULL_TREE);
> > > -	    if (refs_may_alias_p_1 (&dref, ref, false))
> > > -	      return true;
> > > -	    ao_ref_init_from_ptr_and_size (&dref,
> > > -					   gimple_call_arg (call, 1),
> > > -					   NULL_TREE);
> > > -	    return refs_may_alias_p_1 (&dref, ref, false);
> > > -	  }
> > > -
> > > -	/* The following builtins do not read from memory.  */
> > > -	case BUILT_IN_FREE:
> > > -	case BUILT_IN_MALLOC:
> > > -	case BUILT_IN_POSIX_MEMALIGN:
> > > -	case BUILT_IN_ALIGNED_ALLOC:
> > > -	case BUILT_IN_CALLOC:
> > > -	CASE_BUILT_IN_ALLOCA:
> > > -	case BUILT_IN_STACK_SAVE:
> > > -	case BUILT_IN_STACK_RESTORE:
> > > -	case BUILT_IN_MEMSET:
> > > -	case BUILT_IN_TM_MEMSET:
> > > -	case BUILT_IN_MEMSET_CHK:
> > > -	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_SINCOS:
> > > -	case BUILT_IN_SINCOSF:
> > > -	case BUILT_IN_SINCOSL:
> > > -	case BUILT_IN_ASSUME_ALIGNED:
> > > -	case BUILT_IN_VA_END:
> > > +      && gimple_call_builtin_p (call, BUILT_IN_NORMAL)
> > > +      && (ao_classify_builtin (callee, &info)))
> > > +    {
> > > +      if (info.flags & AO_FUNCTION_BARRIER)
> > > +	return true;
> > > +      if (info.num_param_reads >= 0)
> > > +	{
> > > +	  for (int i = 0; i < info.num_param_reads; i++)
> > > +	    {
> > > +	      ao_ref dref;
> > > +	      tree size = NULL_TREE;
> > > +
> > > +	      gcc_checking_assert (info.reads[i].size_param
> > > +				   != info.reads[i].param);
> > > +	      if (info.reads[i].size_param != -1)
> > > +		size = gimple_call_arg (call, info.reads[i].size);
> > > +	      else if (info.reads[i].size)
> > > +		size = build_int_cst (size_type_node, info.reads[i].size);
> > > +	      ao_ref_init_from_ptr_and_size (&dref,
> > > +					     gimple_call_arg
> > > +						 (call,
> > > +						  info.reads[i].param),
> > > +					     size);
> > > +	      if (refs_may_alias_p_1 (&dref, ref, tbaa_p))
> > > +		return true;
> > > +	    }
> > >  	  return false;
> > > -	/* __sync_* builtins and some OpenMP builtins act as threading
> > > -	   barriers.  */
> > > -#undef DEF_SYNC_BUILTIN
> > > -#define DEF_SYNC_BUILTIN(ENUM, NAME, TYPE, ATTRS) case ENUM:
> > > -#include "sync-builtins.def"
> > > -#undef DEF_SYNC_BUILTIN
> > > -	case BUILT_IN_GOMP_ATOMIC_START:
> > > -	case BUILT_IN_GOMP_ATOMIC_END:
> > > -	case BUILT_IN_GOMP_BARRIER:
> > > -	case BUILT_IN_GOMP_BARRIER_CANCEL:
> > > -	case BUILT_IN_GOMP_TASKWAIT:
> > > -	case BUILT_IN_GOMP_TASKGROUP_END:
> > > -	case BUILT_IN_GOMP_CRITICAL_START:
> > > -	case BUILT_IN_GOMP_CRITICAL_END:
> > > -	case BUILT_IN_GOMP_CRITICAL_NAME_START:
> > > -	case BUILT_IN_GOMP_CRITICAL_NAME_END:
> > > -	case BUILT_IN_GOMP_LOOP_END:
> > > -	case BUILT_IN_GOMP_LOOP_END_CANCEL:
> > > -	case BUILT_IN_GOMP_ORDERED_START:
> > > -	case BUILT_IN_GOMP_ORDERED_END:
> > > -	case BUILT_IN_GOMP_SECTIONS_END:
> > > -	case BUILT_IN_GOMP_SECTIONS_END_CANCEL:
> > > -	case BUILT_IN_GOMP_SINGLE_COPY_START:
> > > -	case BUILT_IN_GOMP_SINGLE_COPY_END:
> > > -	  return true;
> > > -
> > > -	default:
> > > -	  /* Fallthru to general call handling.  */;
> > > -      }
> > > +	}
> > > +    }
> > >  
> > >    /* Check if base is a global static variable that is not read
> > >       by the function.  */
> > > @@ -2961,7 +3280,9 @@ call_may_clobber_ref_p_1 (gcall *call, ao_ref *ref, bool tbaa_p)
> > >  	  modref_summary *summary = get_modref_function_summary (node);
> > >  	  if (summary)
> > >  	    {
> > > -	      if (!modref_may_conflict (call, summary->stores, ref, tbaa_p))
> > > +	      if (!modref_may_conflict (call, summary->stores, ref, tbaa_p)
> > > +		  && (!summary->writes_errno
> > > +		      || !targetm.ref_may_alias_errno (ref)))
> > >  		{
> > >  		  alias_stats.modref_clobber_no_alias++;
> > >  		  if (dump_file && (dump_flags & TDF_DETAILS))
> > > @@ -3016,205 +3337,43 @@ call_may_clobber_ref_p_1 (gcall *call, ao_ref *ref, bool tbaa_p)
> > >        && SSA_NAME_POINTS_TO_READONLY_MEMORY (TREE_OPERAND (base, 0)))
> > >      return false;
> > >  
> > > +  struct ao_function_info info;
> > >    /* 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.  */
> > > +     escape points.  */
> > >    if (callee != NULL_TREE
> > > -      && gimple_call_builtin_p (call, 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_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:
> > > -	case BUILT_IN_MEMSET:
> > > -	case BUILT_IN_TM_MEMSET:
> > > -	CASE_BUILT_IN_TM_STORE (1):
> > > -	CASE_BUILT_IN_TM_STORE (2):
> > > -	CASE_BUILT_IN_TM_STORE (4):
> > > -	CASE_BUILT_IN_TM_STORE (8):
> > > -	CASE_BUILT_IN_TM_STORE (FLOAT):
> > > -	CASE_BUILT_IN_TM_STORE (DOUBLE):
> > > -	CASE_BUILT_IN_TM_STORE (LDOUBLE):
> > > -	CASE_BUILT_IN_TM_STORE (M64):
> > > -	CASE_BUILT_IN_TM_STORE (M128):
> > > -	CASE_BUILT_IN_TM_STORE (M256):
> > > -	case BUILT_IN_TM_MEMCPY:
> > > -	case BUILT_IN_TM_MEMMOVE:
> > > -	  {
> > > -	    ao_ref dref;
> > > -	    tree size = NULL_TREE;
> > > -	    /* Don't pass in size for strncat, as the maximum size
> > > -	       is strlen (dest) + n + 1 instead of n, resp.
> > > -	       n + 1 at dest + strlen (dest), but strlen (dest) isn't
> > > -	       known.  */
> > > -	    if (gimple_call_num_args (call) == 3
> > > -		&& DECL_FUNCTION_CODE (callee) != BUILT_IN_STRNCAT)
> > > -	      size = gimple_call_arg (call, 2);
> > > -	    ao_ref_init_from_ptr_and_size (&dref,
> > > -					   gimple_call_arg (call, 0),
> > > -					   size);
> > > -	    return refs_may_alias_p_1 (&dref, ref, false);
> > > -	  }
> > > -	case BUILT_IN_STRCPY_CHK:
> > > -	case BUILT_IN_STRNCPY_CHK:
> > > -	case BUILT_IN_MEMCPY_CHK:
> > > -	case BUILT_IN_MEMMOVE_CHK:
> > > -	case BUILT_IN_MEMPCPY_CHK:
> > > -	case BUILT_IN_STPCPY_CHK:
> > > -	case BUILT_IN_STPNCPY_CHK:
> > > -	case BUILT_IN_STRCAT_CHK:
> > > -	case BUILT_IN_STRNCAT_CHK:
> > > -	case BUILT_IN_MEMSET_CHK:
> > > -	  {
> > > -	    ao_ref dref;
> > > -	    tree size = NULL_TREE;
> > > -	    /* Don't pass in size for __strncat_chk, as the maximum size
> > > -	       is strlen (dest) + n + 1 instead of n, resp.
> > > -	       n + 1 at dest + strlen (dest), but strlen (dest) isn't
> > > -	       known.  */
> > > -	    if (gimple_call_num_args (call) == 4
> > > -		&& DECL_FUNCTION_CODE (callee) != BUILT_IN_STRNCAT_CHK)
> > > -	      size = gimple_call_arg (call, 2);
> > > -	    ao_ref_init_from_ptr_and_size (&dref,
> > > -					   gimple_call_arg (call, 0),
> > > -					   size);
> > > -	    return refs_may_alias_p_1 (&dref, ref, false);
> > > -	  }
> > > -	case BUILT_IN_BCOPY:
> > > -	  {
> > > -	    ao_ref dref;
> > > -	    tree size = gimple_call_arg (call, 2);
> > > -	    ao_ref_init_from_ptr_and_size (&dref,
> > > -					   gimple_call_arg (call, 1),
> > > -					   size);
> > > -	    return refs_may_alias_p_1 (&dref, ref, false);
> > > -	  }
> > > -	/* Allocating memory does not have any side-effects apart from
> > > -	   being the definition point for the pointer.  */
> > > -	case BUILT_IN_MALLOC:
> > > -	case BUILT_IN_ALIGNED_ALLOC:
> > > -	case BUILT_IN_CALLOC:
> > > -	case BUILT_IN_STRDUP:
> > > -	case BUILT_IN_STRNDUP:
> > > -	  /* Unix98 specifies that errno is set on allocation failure.  */
> > > -	  if (flag_errno_math
> > > -	      && targetm.ref_may_alias_errno (ref))
> > > -	    return true;
> > > -	  return false;
> > > -	case BUILT_IN_STACK_SAVE:
> > > -	CASE_BUILT_IN_ALLOCA:
> > > -	case BUILT_IN_ASSUME_ALIGNED:
> > > +      && gimple_call_builtin_p (call, BUILT_IN_NORMAL)
> > > +      && (ao_classify_builtin (callee, &info)))
> > > +    {
> > > +      if (info.flags & AO_FUNCTION_BARRIER)
> > > +	return true;
> > > +      if ((info.flags & AO_FUNCTION_ERRNO)
> > > +	  && flag_errno_math
> > > +	  && targetm.ref_may_alias_errno (ref))
> > > +	return true;
> > > +      if (info.num_param_writes >= 0)
> > > +	{
> > > +	  for (int i = 0; i < info.num_param_writes; i++)
> > > +	    {
> > > +	      ao_ref dref;
> > > +	      tree size = NULL_TREE;
> > > +
> > > +	      gcc_checking_assert (info.writes[i].size_param
> > > +				   != info.writes[i].param);
> > > +	      if (info.writes[i].size_param != -1)
> > > +		size = gimple_call_arg (call, info.writes[i].size_param);
> > > +	      else if (info.writes[i].size)
> > > +		size = build_int_cst (size_type_node, info.writes[i].size);
> > > +	      ao_ref_init_from_ptr_and_size (&dref,
> > > +					     gimple_call_arg
> > > +						 (call,
> > > +						  info.writes[i].param),
> > > +					     size);
> > > +	      if (refs_may_alias_p_1 (&dref, ref, tbaa_p))
> > > +		return true;
> > > +	    }
> > >  	  return false;
> > > -	/* But posix_memalign stores a pointer into the memory pointed to
> > > -	   by its first argument.  */
> > > -	case BUILT_IN_POSIX_MEMALIGN:
> > > -	  {
> > > -	    tree ptrptr = gimple_call_arg (call, 0);
> > > -	    ao_ref dref;
> > > -	    ao_ref_init_from_ptr_and_size (&dref, ptrptr,
> > > -					   TYPE_SIZE_UNIT (ptr_type_node));
> > > -	    return (refs_may_alias_p_1 (&dref, ref, false)
> > > -		    || (flag_errno_math
> > > -			&& targetm.ref_may_alias_errno (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.  */
> > > -	case BUILT_IN_FREE:
> > > -	case BUILT_IN_VA_END:
> > > -	  {
> > > -	    tree ptr = gimple_call_arg (call, 0);
> > > -	    return ptr_deref_may_alias_ref_p_1 (ptr, ref);
> > > -	  }
> > > -	/* Realloc serves both as allocation point and deallocation point.  */
> > > -	case BUILT_IN_REALLOC:
> > > -	  {
> > > -	    tree ptr = gimple_call_arg (call, 0);
> > > -	    /* Unix98 specifies that errno is set on allocation failure.  */
> > > -	    return ((flag_errno_math
> > > -		     && targetm.ref_may_alias_errno (ref))
> > > -		    || ptr_deref_may_alias_ref_p_1 (ptr, ref));
> > > -	  }
> > > -	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:
> > > -	  {
> > > -	    tree out = gimple_call_arg (call, 1);
> > > -	    if (ptr_deref_may_alias_ref_p_1 (out, ref))
> > > -	      return true;
> > > -	    if (flag_errno_math)
> > > -	      break;
> > > -	    return false;
> > > -	  }
> > > -	case BUILT_IN_FREXP:
> > > -	case BUILT_IN_FREXPF:
> > > -	case BUILT_IN_FREXPL:
> > > -	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_1 (out, ref);
> > > -	  }
> > > -	case BUILT_IN_REMQUO:
> > > -	case BUILT_IN_REMQUOF:
> > > -	case BUILT_IN_REMQUOL:
> > > -	  {
> > > -	    tree out = gimple_call_arg (call, 2);
> > > -	    if (ptr_deref_may_alias_ref_p_1 (out, ref))
> > > -	      return true;
> > > -	    if (flag_errno_math)
> > > -	      break;
> > > -	    return false;
> > > -	  }
> > > -	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);
> > > -	    return (ptr_deref_may_alias_ref_p_1 (sin, ref)
> > > -		    || ptr_deref_may_alias_ref_p_1 (cos, ref));
> > > -	  }
> > > -	/* __sync_* builtins and some OpenMP builtins act as threading
> > > -	   barriers.  */
> > > -#undef DEF_SYNC_BUILTIN
> > > -#define DEF_SYNC_BUILTIN(ENUM, NAME, TYPE, ATTRS) case ENUM:
> > > -#include "sync-builtins.def"
> > > -#undef DEF_SYNC_BUILTIN
> > > -	case BUILT_IN_GOMP_ATOMIC_START:
> > > -	case BUILT_IN_GOMP_ATOMIC_END:
> > > -	case BUILT_IN_GOMP_BARRIER:
> > > -	case BUILT_IN_GOMP_BARRIER_CANCEL:
> > > -	case BUILT_IN_GOMP_TASKWAIT:
> > > -	case BUILT_IN_GOMP_TASKGROUP_END:
> > > -	case BUILT_IN_GOMP_CRITICAL_START:
> > > -	case BUILT_IN_GOMP_CRITICAL_END:
> > > -	case BUILT_IN_GOMP_CRITICAL_NAME_START:
> > > -	case BUILT_IN_GOMP_CRITICAL_NAME_END:
> > > -	case BUILT_IN_GOMP_LOOP_END:
> > > -	case BUILT_IN_GOMP_LOOP_END_CANCEL:
> > > -	case BUILT_IN_GOMP_ORDERED_START:
> > > -	case BUILT_IN_GOMP_ORDERED_END:
> > > -	case BUILT_IN_GOMP_SECTIONS_END:
> > > -	case BUILT_IN_GOMP_SECTIONS_END_CANCEL:
> > > -	case BUILT_IN_GOMP_SINGLE_COPY_START:
> > > -	case BUILT_IN_GOMP_SINGLE_COPY_END:
> > > -	  return true;
> > > -	default:
> > > -	  /* Fallthru to general call handling.  */;
> > > -      }
> > > +	}
> > > +    }
> > >  
> > >    /* Check if base is a global static variable that is not written
> > >       by the function.  */
> > > 
> > 
> > -- 
> > Richard Biener <rguenther@suse.de>
> > SUSE Software Solutions Germany GmbH, Maxfeldstrasse 5, 90409 Nuernberg,
> > Germany; GF: Felix Imend
> 
>
Jan Hubicka Sept. 28, 2020, 10:08 a.m. UTC | #4
> 
> Hmm, no - it expects the gimple_call_use/clobber_set to include
> actions of the called function itself (const functions none here)
> but for passed-by-value the loads may be in the call itself
> which is where it uses gimple_call_arg_flags to skip unused ones.
> 
> But note that PTA uses gimple_call_arg_flags to compute
> the gimple_call_use/clobber_set (but only in IPA mode) and the individual 
> BUILT_IN_* handlings in tree-ssa-alias.c do what PTA would do
> here, just directly as alias queries.  Originally I tried adding
> "fn spec"s to BUILT_IN_* decls but that got out-of-hands ...

Yep, I was also looking into that, it looks ugly and moreover the
attributes that depend on flag_math_errno and friends does not really
work for function speicfic attributes, so it is bug we handle them this
way.

Packing this into descriptor string in fnspec rather than descriptor
sturcture returned on side works for me (and we could add them to thinws
like C++ toplevel new/delete operator)
> 
> For example
> 
>         /* All the following functions read memory pointed to by
>            their second argument.  strcat/strncat additionally
>            reads memory pointed to by the first argument.  */
>         case BUILT_IN_STRCAT:
>         case BUILT_IN_STRNCAT:
>           {
>             ao_ref dref;
>             ao_ref_init_from_ptr_and_size (&dref,
>                                            gimple_call_arg (call, 0),
>                                            NULL_TREE);
>             if (refs_may_alias_p_1 (&dref, ref, false))
>               return true;
>           }
> 
> would be covered by "1WR" (W also implies read).  So the question
> would be whether at least parts of your patch could be implemented
> by making gimple_call_fnspec () return pre-determined fn-specs
> for BUILT_IN_* (like we do with internal_fn_fnspec).

One important change would be that we still need to figure out if the
function has other side effects.  Currently ref_maybe_used_by_call_p_1
first tries to prove that ref is local and can not be used by the
function unless it is passed as parameter value and then it looks into
fnspec if the parameter is used.

For builtins it constructs tests based on the builtin type and bypasses
the rest since it knows that all side effects are understood.

As far as I can tell, fn spec isused only by fortran for library calls,
so perhaps it would not be too hard to turn fn spec semantics from "some
properties of parameter handling are known" to "all memory accesses are
known" or have additional way to indicate this.

I guess space in return value predictor could be reserved for this, or
we could have extra flags section at the begining.

> 
> >  We would need
> > to invent how to add info that non pure/const function only access the
> > argument according to fn spec, add way to represent sizes of accesses
> > and how to handle errno.
> 
> True - fn-spec lacks an ability to specify access size - fortunately
> it's internal and we could change it ;)  Whether or not sth can clobber
> errno is sth we eventually need to move to the stmt level anyway
> (-f[no-]math-errno crossing inline boundary) - bit sad to waste a
> bit in a gimple call for this though.  OTOH we waste a ton of space
> in the call_used/call_clobbered members due to bad packing
> (unsigned int bitfield followed by a pointer to a bitmap).  Eventually
> we could offload this kind of info from the main stmt.  We could
> also allocate a fake UID to represent errno (but then the rest of
> the bits in call_used/call_clobbered have to be precise) - but note
> call_used/call_clobbered does not transfer during inlining.
> 
> So for the access size issue we could blow up fnspec by factor of two,
> reserving two chars per argument/return value and do
> 
>  1.W3R.

We also have known bytesizes like return values of sincos
(where the size really matters on the size of type that is known only at
runtime).
That can be 3 digits if represented decimally (or two digits hex, but
it may become too small in future with vector types)

One option would be make the unit to be the size of pointer pointed to,
tat would turn it to be 1 in all cases we handle. Then we could blow up
by 3 and have something like P1 meaning "size is described by parameter
numer 1" and "10" meaning 10 elements are written by the function.
> 
> for strncat plus add gimple_call_arg_size to access it.  The 2nd
> slot in return value could host the errno thing (eh).
> 
>  .e
> 
> for sqrt for example.
> 
> Just to repeat again - the info looks too similar to warrant an
> extra mechanism to record it.

No problem, just if we figure way to do so :)
> 
> Richard.
> 
> > Honza
> > > 
> > > > gcc/ChangeLog:
> > > > 
> > > > 2020-09-28  Jan Hubicka  <hubicka@ucw.cz>
> > > > 
> > > > 	* tree-ssa-alias.c (ao_classify_builtin): New function commonizing
> > > > 	logic from ...
> > > > 	(ref_maybe_used_by_call_p_1): ... here.
> > > > 	(call_may_clobber_ref_p_1): ... and here.
> > > > 	* tree-ssa-alias.h (enum ao_function_flags): New enum.
> > > > 	(struct ao_function_info): New structure.
> > > > 	(ao_classify_builtin): Declare.
> > > > 
> > > > diff --git a/gcc/tree-ssa-alias.h b/gcc/tree-ssa-alias.h
> > > > index 1dd02c0ea62..eecb8da6dd7 100644
> > > > --- a/gcc/tree-ssa-alias.h
> > > > +++ b/gcc/tree-ssa-alias.h
> > > > @@ -108,6 +108,33 @@ ao_ref::max_size_known_p () const
> > > >    return known_size_p (max_size);
> > > >  }
> > > >  
> > > > +/* Flags used in ao_function_info.  */
> > > > +
> > > > +enum ao_function_flags
> > > > +{
> > > > +  AO_FUNCTION_BARRIER = 1,
> > > > +  AO_FUNCTION_ERRNO = 2,
> > > > +};
> > > > +
> > > > +/* Describe side effects relevant for alias analysis of function call to
> > > > +   DECL.  */
> > > > +
> > > > +struct ao_function_info
> > > > +{
> > > > +  int num_param_reads;  /* Number of parameters function reads from,
> > > > +			   -1 if reads are unknown.  */
> > > > +  struct ao_access_info
> > > > +    {
> > > > +      char param; 	/* Index of parameter read/written from.  */
> > > > +      char size_param;	/* Index of parameter specifying size of the access,
> > > > +			   -1 if unknown.  */
> > > > +      char size;	/* Size of access if known, 0 if unknown.  */
> > > > +    } reads[2];
> > > > +  int num_param_writes;
> > > > +  struct ao_access_info writes[2];
> > > > +  enum ao_function_flags flags;
> > > > +};
> > > > +
> > > >  /* In tree-ssa-alias.c  */
> > > >  extern void ao_ref_init (ao_ref *, tree);
> > > >  extern void ao_ref_init_from_ptr_and_size (ao_ref *, tree, tree);
> > > > @@ -158,6 +185,7 @@ extern void debug (pt_solution *ptr);
> > > >  extern void dump_points_to_info_for (FILE *, tree);
> > > >  extern void debug_points_to_info_for (tree);
> > > >  extern void dump_alias_stats (FILE *);
> > > > +extern bool ao_classify_builtin (tree callee, ao_function_info *info);
> > > >  
> > > >  
> > > >  /* In tree-ssa-structalias.c  */
> > > > diff --git a/gcc/tree-ssa-alias.c b/gcc/tree-ssa-alias.c
> > > > index fe390d4ffbe..c182e7bb39c 100644
> > > > --- a/gcc/tree-ssa-alias.c
> > > > +++ b/gcc/tree-ssa-alias.c
> > > > @@ -2503,6 +2503,507 @@ modref_may_conflict (const gimple *stmt,
> > > >    return false;
> > > >  }
> > > >  
> > > > +/* If CALLEE has known side effects, fill in INFO and return true.
> > > > +   See tree-ssa-structalias.c:find_func_aliases
> > > > +   for the list of builtins we might need to handle here.  */
> > > > +
> > > > +bool
> > > > +ao_classify_builtin (tree callee, ao_function_info *info)
> > > > +{
> > > > +  built_in_function code = DECL_FUNCTION_CODE (callee);
> > > > +
> > > > +  switch (code)
> > > > +    {
> > > > +      /* All the following functions read memory pointed to by
> > > > +	 their second argument and write memory pointed to by first
> > > > +	 argument.
> > > > +	 strcat/strncat additionally reads memory pointed to by the first
> > > > +	 argument.  */
> > > > +      case BUILT_IN_STRCAT:
> > > > +	{
> > > > +	  const static struct ao_function_info ret_info
> > > > +	       = {
> > > > +		    2,				/* num_param_reads.  */
> > > > +
> > > > +		    /* Reads and write descriptors are triples containing:
> > > > +		       - index of parameter read
> > > > +		       - index of parameter specifying access size
> > > > +			 (-1 if unknown)
> > > > +		       - access size in bytes (0 if unkown).  */
> > > > +
> > > > +		    {{0, -1, 0}, {1, -1, 0}},	/* Param read.  */
> > > > +		    1,				/* num_param_writes.  */
> > > > +		    {{0, -1, 0}},		/* Param written.  */
> > > > +		    (ao_function_flags)0,	/* flags.  */
> > > > +		 };
> > > > +	  *info = ret_info;
> > > > +	  return true;
> > > > +	}
> > > > +      case BUILT_IN_STRNCAT:
> > > > +	{
> > > > +	  const static struct ao_function_info ret_info
> > > > +	       = {
> > > > +		    2,				/* num_param_reads.  */
> > > > +		    {{0, -1, 0}, {1, 2, 0}},	/* Param read.  */
> > > > +		    1,				/* num_param_writes.  */
> > > > +		    {{0, -1, 0}},		/* Param written.  */
> > > > +		    (ao_function_flags)0,	/* flags.  */
> > > > +		 };
> > > > +	  *info = ret_info;
> > > > +	  return true;
> > > > +	}
> > > > +      case BUILT_IN_STRCPY:
> > > > +      case BUILT_IN_STPCPY:
> > > > +	{
> > > > +	  const static struct ao_function_info ret_info
> > > > +	       = {
> > > > +		    1,				/* num_param_reads.  */
> > > > +		    {{1, -1, 0}},		/* Param read.  */
> > > > +		    1,				/* num_param_writes.  */
> > > > +		    {{0, -1, 0}},		/* Param written.  */
> > > > +		    (ao_function_flags)0,	/* flags.  */
> > > > +		 };
> > > > +	  *info = ret_info;
> > > > +	  return true;
> > > > +	}
> > > > +      case BUILT_IN_STRNCPY:
> > > > +      case BUILT_IN_MEMCPY:
> > > > +      case BUILT_IN_MEMMOVE:
> > > > +      case BUILT_IN_MEMPCPY:
> > > > +      case BUILT_IN_STPNCPY:
> > > > +      case BUILT_IN_TM_MEMCPY:
> > > > +      case BUILT_IN_TM_MEMMOVE:
> > > > +	{
> > > > +	  const static struct ao_function_info ret_info
> > > > +	       = {
> > > > +		    1,				/* num_param_reads.  */
> > > > +		    {{1, 2, 0}},		/* Param read.  */
> > > > +		    1,				/* num_param_writes.  */
> > > > +		    {{0, 2, 0}},		/* Param written.  */
> > > > +		    (ao_function_flags)0,	/* flags.  */
> > > > +		 };
> > > > +	  *info = ret_info;
> > > > +	  return true;
> > > > +	}
> > > > +      case BUILT_IN_STRCAT_CHK:
> > > > +	{
> > > > +	  const static struct ao_function_info ret_info
> > > > +	       = {
> > > > +		    2,				/* num_param_reads.  */
> > > > +		    {{0, -1, 0}, {1, -1, 0}},	/* Param read.  */
> > > > +		    1,				/* num_param_writes.  */
> > > > +		    {{0, -1, 0}},		/* Param written.  */
> > > > +		    (ao_function_flags)0,	/* flags.  */
> > > > +		 };
> > > > +	  *info = ret_info;
> > > > +	  return true;
> > > > +	}
> > > > +      case BUILT_IN_STRNCAT_CHK:
> > > > +	{
> > > > +	  const static struct ao_function_info ret_info
> > > > +	       = {
> > > > +		    2,				/* num_param_reads.  */
> > > > +		    {{0, -1, 0}, {1, 2, 0}},	/* Param read.  */
> > > > +		    1,				/* num_param_writes.  */
> > > > +		    {{0, -1, 0}},		/* Param written.  */
> > > > +		    (ao_function_flags)0,	/* flags.  */
> > > > +		 };
> > > > +	  *info = ret_info;
> > > > +	  return true;
> > > > +	}
> > > > +      case BUILT_IN_STRCPY_CHK:
> > > > +      case BUILT_IN_STPCPY_CHK:
> > > > +	{
> > > > +	  const static struct ao_function_info ret_info
> > > > +	       = {
> > > > +		    1,				/* num_param_reads.  */
> > > > +		    {{1, -1, 0}},		/* Param read.  */
> > > > +		    1,				/* num_param_writes.  */
> > > > +		    {{0, -1, 0}},		/* Param written.  */
> > > > +		    (ao_function_flags)0,	/* flags.  */
> > > > +		 };
> > > > +	  *info = ret_info;
> > > > +	  return true;
> > > > +	}
> > > > +      case BUILT_IN_STRNCPY_CHK:
> > > > +      case BUILT_IN_MEMCPY_CHK:
> > > > +      case BUILT_IN_MEMMOVE_CHK:
> > > > +      case BUILT_IN_MEMPCPY_CHK:
> > > > +      case BUILT_IN_STPNCPY_CHK:
> > > > +	{
> > > > +	  const static struct ao_function_info ret_info
> > > > +	       = {
> > > > +		    1,				/* num_param_reads.  */
> > > > +		    {{1, 2, 0}},		/* Param read.  */
> > > > +		    1,				/* num_param_writes.  */
> > > > +		    {{0, 2, 0}},		/* Param written.  */
> > > > +		    (ao_function_flags)0,	/* flags.  */
> > > > +		 };
> > > > +	  *info = ret_info;
> > > > +	  return true;
> > > > +	}
> > > > +      case BUILT_IN_BCOPY:
> > > > +	{
> > > > +	  const static struct ao_function_info ret_info
> > > > +	       = {
> > > > +		    1,				/* num_param_reads.  */
> > > > +		    {{0, 2, 0}},		/* Param read.  */
> > > > +		    1,				/* num_param_writes.  */
> > > > +		    {{1, 2, 0}},		/* Param written.  */
> > > > +		    (ao_function_flags)0,	/* flags.  */
> > > > +		 };
> > > > +	  *info = ret_info;
> > > > +	  return true;
> > > > +	}
> > > > +
> > > > +      /* The following functions read memory pointed to by their
> > > > +	 first argument.  */
> > > > +      CASE_BUILT_IN_TM_LOAD (1):
> > > > +      CASE_BUILT_IN_TM_LOAD (2):
> > > > +      CASE_BUILT_IN_TM_LOAD (4):
> > > > +      CASE_BUILT_IN_TM_LOAD (8):
> > > > +      CASE_BUILT_IN_TM_LOAD (FLOAT):
> > > > +      CASE_BUILT_IN_TM_LOAD (DOUBLE):
> > > > +      CASE_BUILT_IN_TM_LOAD (LDOUBLE):
> > > > +      CASE_BUILT_IN_TM_LOAD (M64):
> > > > +      CASE_BUILT_IN_TM_LOAD (M128):
> > > > +      CASE_BUILT_IN_TM_LOAD (M256):
> > > > +      case BUILT_IN_TM_LOG:
> > > > +      case BUILT_IN_TM_LOG_1:
> > > > +      case BUILT_IN_TM_LOG_2:
> > > > +      case BUILT_IN_TM_LOG_4:
> > > > +      case BUILT_IN_TM_LOG_8:
> > > > +      case BUILT_IN_TM_LOG_FLOAT:
> > > > +      case BUILT_IN_TM_LOG_DOUBLE:
> > > > +      case BUILT_IN_TM_LOG_LDOUBLE:
> > > > +      case BUILT_IN_TM_LOG_M64:
> > > > +      case BUILT_IN_TM_LOG_M128:
> > > > +      case BUILT_IN_TM_LOG_M256:
> > > > +
> > > > +      case BUILT_IN_INDEX:
> > > > +      case BUILT_IN_STRCHR:
> > > > +      case BUILT_IN_STRRCHR:
> > > > +	{
> > > > +	  const static struct ao_function_info ret_info
> > > > +	       = {
> > > > +		    1,				/* num_param_reads.  */
> > > > +		    /* TODO: For TM builtins size is known.  */
> > > > +		    {{0, -1, 0}},		/* Param read.  */
> > > > +		    0,				/* num_param_writes.  */
> > > > +		    {},				/* Param written.  */
> > > > +		    (ao_function_flags)0,	/* flags.  */
> > > > +		 };
> > > > +	  *info = ret_info;
> > > > +	  return true;
> > > > +	}
> > > > +
> > > > +      /* These read memory pointed to by the first argument.
> > > > +	 Allocating memory does not have any side-effects apart from
> > > > +	 being the definition point for the pointer.
> > > > +	 Unix98 specifies that errno is set on allocation failure.  */
> > > > +      case BUILT_IN_STRDUP:
> > > > +	{
> > > > +	  const static struct ao_function_info ret_info
> > > > +	       = {
> > > > +		    1,				/* num_param_reads.  */
> > > > +		    {{0, -1, 0}},		/* Param read.  */
> > > > +		    0,				/* num_param_writes.  */
> > > > +		    {},				/* Param written.  */
> > > > +		    AO_FUNCTION_ERRNO,		/* flags.  */
> > > > +		 };
> > > > +	  *info = ret_info;
> > > > +	  return true;
> > > > +	}
> > > > +      case BUILT_IN_STRNDUP:
> > > > +	{
> > > > +	  const static struct ao_function_info ret_info
> > > > +	       = {
> > > > +		    1,				/* num_param_reads.  */
> > > > +		    {{0, 1, 0}},		/* Param read.  */
> > > > +		    0,				/* num_param_writes.  */
> > > > +		    {},				/* Param written.  */
> > > > +		    AO_FUNCTION_ERRNO,		/* flags.  */
> > > > +		 };
> > > > +	  *info = ret_info;
> > > > +	  return true;
> > > > +	}
> > > > +      /* Allocating memory does not have any side-effects apart from
> > > > +	 being the definition point for the pointer.  */
> > > > +      case BUILT_IN_MALLOC:
> > > > +      case BUILT_IN_ALIGNED_ALLOC:
> > > > +      case BUILT_IN_CALLOC:
> > > > +	{
> > > > +	  const static struct ao_function_info ret_info
> > > > +	       = {
> > > > +		    0,				/* num_param_reads.  */
> > > > +		    {},				/* Param read.  */
> > > > +		    0,				/* num_param_writes.  */
> > > > +		    {},				/* Param written.  */
> > > > +		    AO_FUNCTION_ERRNO,		/* flags.  */
> > > > +		 };
> > > > +	  *info = ret_info;
> > > > +	  return true;
> > > > +	}
> > > > +      /* These read memory pointed to by the first argument with size
> > > > +	 in the third argument.  */
> > > > +      case BUILT_IN_MEMCHR:
> > > > +	{
> > > > +	  const static struct ao_function_info ret_info
> > > > +	       = {
> > > > +		    1,				/* num_param_reads.  */
> > > > +		    {{0, 2, 0}},		/* Param read.  */
> > > > +		    0,				/* num_param_writes.  */
> > > > +		    {},				/* Param written.  */
> > > > +		    (ao_function_flags)0,	/* flags.  */
> > > > +		 };
> > > > +	  *info = ret_info;
> > > > +	  return true;
> > > > +	}
> > > > +      /* These read memory pointed to by the first and second arguments.  */
> > > > +      case BUILT_IN_STRSTR:
> > > > +      case BUILT_IN_STRPBRK:
> > > > +	{
> > > > +	  static struct ao_function_info ret_info
> > > > +	       = {
> > > > +		    2,				/* num_param_reads.  */
> > > > +		    {{0, -1, 0}, {1, -1, 0}},	/* Param read.  */
> > > > +		    0,				/* num_param_writes.  */
> > > > +		    {},				/* Param written.  */
> > > > +		    (ao_function_flags)0,	/* flags.  */
> > > > +		 };
> > > > +	  *info = ret_info;
> > > > +	  return true;
> > > > +	}
> > > > +      /* Freeing memory kills the pointed-to memory.  More importantly
> > > > +	 the call has to serve as a barrier for moving loads and stores
> > > > +	 across it.  */
> > > > +      case BUILT_IN_FREE:
> > > > +      case BUILT_IN_VA_END:
> > > > +	{
> > > > +	  const static struct ao_function_info ret_info
> > > > +	       = {
> > > > +		    0,				/* num_param_reads.  */
> > > > +		    {},				/* Param read.  */
> > > > +		    1,				/* num_param_writes.  */
> > > > +		    {{0, -1, 0}},		/* Param written.  */
> > > > +		    (ao_function_flags)0,	/* flags.  */
> > > > +		 };
> > > > +	  *info = ret_info;
> > > > +	  return true;
> > > > +	}
> > > > +      /* Realloc serves both as allocation point and deallocation point.  */
> > > > +      case BUILT_IN_REALLOC:
> > > > +	{
> > > > +	  const static struct ao_function_info ret_info
> > > > +	       = {
> > > > +		    1,				/* num_param_reads.  */
> > > > +		    {{0, 1, 0}},		/* Param read.  */
> > > > +		    0,				/* num_param_writes.  */
> > > > +		    {{0, -1, 0}},		/* Param written.  */
> > > > +		    AO_FUNCTION_ERRNO,		/* flags.  */
> > > > +		 };
> > > > +	  *info = ret_info;
> > > > +	  return true;
> > > > +	}
> > > > +      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:
> > > > +	{
> > > > +	  const static struct ao_function_info ret_info
> > > > +	       = {
> > > > +		    0,				/* num_param_reads.  */
> > > > +		    {},				/* Param read.  */
> > > > +		    1,				/* num_param_writes.  */
> > > > +		    {{1, -1, 0}},		/* Param written.  */
> > > > +		    AO_FUNCTION_ERRNO,		/* flags.  */
> > > > +		 };
> > > > +	  *info = ret_info;
> > > > +	  return true;
> > > > +	}
> > > > +      case BUILT_IN_FREXP:
> > > > +      case BUILT_IN_FREXPF:
> > > > +      case BUILT_IN_FREXPL:
> > > > +      case BUILT_IN_MODF:
> > > > +      case BUILT_IN_MODFF:
> > > > +      case BUILT_IN_MODFL:
> > > > +	{
> > > > +	  const static struct ao_function_info ret_info
> > > > +	       = {
> > > > +		    0,				/* num_param_reads.  */
> > > > +		    {},				/* Param read.  */
> > > > +		    1,				/* num_param_writes.  */
> > > > +		    {{1, -1, 0}},		/* Param written.  */
> > > > +		    (ao_function_flags)0,	/* flags.  */
> > > > +		 };
> > > > +	  *info = ret_info;
> > > > +	  return true;
> > > > +	}
> > > > +      case BUILT_IN_REMQUO:
> > > > +      case BUILT_IN_REMQUOF:
> > > > +      case BUILT_IN_REMQUOL:
> > > > +	{
> > > > +	  const static struct ao_function_info ret_info
> > > > +	       = {
> > > > +		    0,				/* num_param_reads.  */
> > > > +		    {},				/* Param read.  */
> > > > +		    1,				/* num_param_writes.  */
> > > > +		    {{2, -1, 0}},		/* Param written.  */
> > > > +		    (ao_function_flags)0,	/* flags.  */
> > > > +		 };
> > > > +	  *info = ret_info;
> > > > +	  return true;
> > > > +	}
> > > > +      case BUILT_IN_SINCOS:
> > > > +      case BUILT_IN_SINCOSF:
> > > > +      case BUILT_IN_SINCOSL:
> > > > +	{
> > > > +	  static struct ao_function_info ret_info
> > > > +	       = {
> > > > +		    0,				/* num_param_reads.  */
> > > > +		    {},				/* Param read.  */
> > > > +		    1,				/* num_param_writes.  */
> > > > +		    {{1, -1, 0}, {2, -1, 0}},	/* Param written.  */
> > > > +		    (ao_function_flags)0,	/* flags.  */
> > > > +		 };
> > > > +	  tree type = float_ptr_type_node;
> > > > +	  if (code == BUILT_IN_SINCOS)
> > > > +	    type = double_ptr_type_node;
> > > > +	  else
> > > > +	    type = long_double_ptr_type_node;
> > > > +	  ret_info.writes[0].size = ret_info.writes[1].size
> > > > +		 = tree_to_uhwi (TYPE_SIZE_UNIT (type));
> > > > +	  *info = ret_info;
> > > > +	  return true;
> > > > +	}
> > > > +      case BUILT_IN_MEMSET:
> > > > +      case BUILT_IN_MEMSET_CHK:
> > > > +      case BUILT_IN_TM_MEMSET:
> > > > +	{
> > > > +	  const static struct ao_function_info ret_info
> > > > +	       = {
> > > > +		    0,				/* num_param_reads.  */
> > > > +		    {},				/* Param read.  */
> > > > +		    1,				/* num_param_writes.  */
> > > > +		    {0, 2, 0},			/* Param written.  */
> > > > +		    (ao_function_flags)0,	/* flags.  */
> > > > +		 };
> > > > +	  *info = ret_info;
> > > > +	  return true;
> > > > +	}
> > > > +      CASE_BUILT_IN_TM_STORE (1):
> > > > +      CASE_BUILT_IN_TM_STORE (2):
> > > > +      CASE_BUILT_IN_TM_STORE (4):
> > > > +      CASE_BUILT_IN_TM_STORE (8):
> > > > +      CASE_BUILT_IN_TM_STORE (FLOAT):
> > > > +      CASE_BUILT_IN_TM_STORE (DOUBLE):
> > > > +      CASE_BUILT_IN_TM_STORE (LDOUBLE):
> > > > +      CASE_BUILT_IN_TM_STORE (M64):
> > > > +      CASE_BUILT_IN_TM_STORE (M128):
> > > > +      CASE_BUILT_IN_TM_STORE (M256):
> > > > +	{
> > > > +	  const static struct ao_function_info ret_info
> > > > +	       = {
> > > > +		    0,				/* num_param_reads.  */
> > > > +		    {},				/* Param read.  */
> > > > +		    1,				/* num_param_writes.  */
> > > > +		    /* TODO: Size is known.  */
> > > > +		    {0, -1, 0},			/* Param written.  */
> > > > +		    (ao_function_flags)0,	/* flags.  */
> > > > +		 };
> > > > +	  *info = ret_info;
> > > > +	  return true;
> > > > +	}
> > > > +      case BUILT_IN_STACK_SAVE:
> > > > +      CASE_BUILT_IN_ALLOCA:
> > > > +      case BUILT_IN_ASSUME_ALIGNED:
> > > > +	{
> > > > +	  const static struct ao_function_info ret_info
> > > > +	       = {
> > > > +		    0,				/* num_param_reads.  */
> > > > +		    {},				/* Param read.  */
> > > > +		    0,				/* num_param_writes.  */
> > > > +		    {},				/* Param written.  */
> > > > +		    (ao_function_flags)0,	/* flags.  */
> > > > +		 };
> > > > +	  *info = ret_info;
> > > > +	  return true;
> > > > +	}
> > > > +      /* But posix_memalign stores a pointer into the memory pointed to
> > > > +	 by its first argument.  */
> > > > +      case BUILT_IN_POSIX_MEMALIGN:
> > > > +	{
> > > > +	  static struct ao_function_info ret_info
> > > > +	       = {
> > > > +		    0,				/* num_param_reads.  */
> > > > +		    {},				/* Param read.  */
> > > > +		    0,				/* num_param_writes.  */
> > > > +		    {{0, -1, 0}},		/* Param written.  */
> > > > +		    AO_FUNCTION_ERRNO,		/* flags.  */
> > > > +		 };
> > > > +	  ret_info.writes[0].size
> > > > +		 = tree_to_uhwi (TYPE_SIZE_UNIT (ptr_type_node));
> > > > +	  *info = ret_info;
> > > > +	  return true;
> > > > +	}
> > > > +      /* The following builtins do not read from memory.  */
> > > > +      case BUILT_IN_STACK_RESTORE:
> > > > +	{
> > > > +	  const static struct ao_function_info ret_info
> > > > +	       = {
> > > > +		    0,				/* num_param_reads.  */
> > > > +		    {},				/* Param read.  */
> > > > +		    0,				/* num_param_writes.  */
> > > > +		    {},				/* Param written.  */
> > > > +		    (ao_function_flags)0,	/* flags.  */
> > > > +		 };
> > > > +	  *info = ret_info;
> > > > +	  return true;
> > > > +	}
> > > > +      /* __sync_* builtins and some OpenMP builtins act as threading
> > > > +	 barriers.  */
> > > > +#undef DEF_SYNC_BUILTIN
> > > > +#define DEF_SYNC_BUILTIN(ENUM, NAME, TYPE, ATTRS) case ENUM:
> > > > +#include "sync-builtins.def"
> > > > +#undef DEF_SYNC_BUILTIN
> > > > +      case BUILT_IN_GOMP_ATOMIC_START:
> > > > +      case BUILT_IN_GOMP_ATOMIC_END:
> > > > +      case BUILT_IN_GOMP_BARRIER:
> > > > +      case BUILT_IN_GOMP_BARRIER_CANCEL:
> > > > +      case BUILT_IN_GOMP_TASKWAIT:
> > > > +      case BUILT_IN_GOMP_TASKGROUP_END:
> > > > +      case BUILT_IN_GOMP_CRITICAL_START:
> > > > +      case BUILT_IN_GOMP_CRITICAL_END:
> > > > +      case BUILT_IN_GOMP_CRITICAL_NAME_START:
> > > > +      case BUILT_IN_GOMP_CRITICAL_NAME_END:
> > > > +      case BUILT_IN_GOMP_LOOP_END:
> > > > +      case BUILT_IN_GOMP_LOOP_END_CANCEL:
> > > > +      case BUILT_IN_GOMP_ORDERED_START:
> > > > +      case BUILT_IN_GOMP_ORDERED_END:
> > > > +      case BUILT_IN_GOMP_SECTIONS_END:
> > > > +      case BUILT_IN_GOMP_SECTIONS_END_CANCEL:
> > > > +      case BUILT_IN_GOMP_SINGLE_COPY_START:
> > > > +      case BUILT_IN_GOMP_SINGLE_COPY_END:
> > > > +	{
> > > > +	  const static struct ao_function_info ret_info
> > > > +	       = {
> > > > +		    -1,				/* num_param_reads.  */
> > > > +		    {},				/* Param read.  */
> > > > +		    -1,				/* num_param_writes.  */
> > > > +		    {},				/* Param written.  */
> > > > +		    AO_FUNCTION_BARRIER,	/* flags.  */
> > > > +		 };
> > > > +	  *info = ret_info;
> > > > +	  return true;
> > > > +	}
> > > > +
> > > > +      default:
> > > > +	return false;
> > > > +    }
> > > > +}
> > > > +
> > > >  /* If the call CALL may use the memory reference REF return true,
> > > >     otherwise return false.  */
> > > >  
> > > > @@ -2574,219 +3075,37 @@ ref_maybe_used_by_call_p_1 (gcall *call, ao_ref *ref, bool tbaa_p)
> > > >    /* 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.  */
> > > > +  struct ao_function_info info;
> > > >    if (callee != NULL_TREE
> > > > -      && gimple_call_builtin_p (call, BUILT_IN_NORMAL))
> > > > -    switch (DECL_FUNCTION_CODE (callee))
> > > > -      {
> > > > -	/* All the following functions read memory pointed to by
> > > > -	   their second argument.  strcat/strncat additionally
> > > > -	   reads memory pointed to by the first argument.  */
> > > > -	case BUILT_IN_STRCAT:
> > > > -	case BUILT_IN_STRNCAT:
> > > > -	  {
> > > > -	    ao_ref dref;
> > > > -	    ao_ref_init_from_ptr_and_size (&dref,
> > > > -					   gimple_call_arg (call, 0),
> > > > -					   NULL_TREE);
> > > > -	    if (refs_may_alias_p_1 (&dref, ref, false))
> > > > -	      return true;
> > > > -	  }
> > > > -	  /* FALLTHRU */
> > > > -	case BUILT_IN_STRCPY:
> > > > -	case BUILT_IN_STRNCPY:
> > > > -	case BUILT_IN_MEMCPY:
> > > > -	case BUILT_IN_MEMMOVE:
> > > > -	case BUILT_IN_MEMPCPY:
> > > > -	case BUILT_IN_STPCPY:
> > > > -	case BUILT_IN_STPNCPY:
> > > > -	case BUILT_IN_TM_MEMCPY:
> > > > -	case BUILT_IN_TM_MEMMOVE:
> > > > -	  {
> > > > -	    ao_ref dref;
> > > > -	    tree size = NULL_TREE;
> > > > -	    if (gimple_call_num_args (call) == 3)
> > > > -	      size = gimple_call_arg (call, 2);
> > > > -	    ao_ref_init_from_ptr_and_size (&dref,
> > > > -					   gimple_call_arg (call, 1),
> > > > -					   size);
> > > > -	    return refs_may_alias_p_1 (&dref, ref, false);
> > > > -	  }
> > > > -	case BUILT_IN_STRCAT_CHK:
> > > > -	case BUILT_IN_STRNCAT_CHK:
> > > > -	  {
> > > > -	    ao_ref dref;
> > > > -	    ao_ref_init_from_ptr_and_size (&dref,
> > > > -					   gimple_call_arg (call, 0),
> > > > -					   NULL_TREE);
> > > > -	    if (refs_may_alias_p_1 (&dref, ref, false))
> > > > -	      return true;
> > > > -	  }
> > > > -	  /* FALLTHRU */
> > > > -	case BUILT_IN_STRCPY_CHK:
> > > > -	case BUILT_IN_STRNCPY_CHK:
> > > > -	case BUILT_IN_MEMCPY_CHK:
> > > > -	case BUILT_IN_MEMMOVE_CHK:
> > > > -	case BUILT_IN_MEMPCPY_CHK:
> > > > -	case BUILT_IN_STPCPY_CHK:
> > > > -	case BUILT_IN_STPNCPY_CHK:
> > > > -	  {
> > > > -	    ao_ref dref;
> > > > -	    tree size = NULL_TREE;
> > > > -	    if (gimple_call_num_args (call) == 4)
> > > > -	      size = gimple_call_arg (call, 2);
> > > > -	    ao_ref_init_from_ptr_and_size (&dref,
> > > > -					   gimple_call_arg (call, 1),
> > > > -					   size);
> > > > -	    return refs_may_alias_p_1 (&dref, ref, false);
> > > > -	  }
> > > > -	case BUILT_IN_BCOPY:
> > > > -	  {
> > > > -	    ao_ref dref;
> > > > -	    tree size = gimple_call_arg (call, 2);
> > > > -	    ao_ref_init_from_ptr_and_size (&dref,
> > > > -					   gimple_call_arg (call, 0),
> > > > -					   size);
> > > > -	    return refs_may_alias_p_1 (&dref, ref, false);
> > > > -	  }
> > > > -
> > > > -	/* The following functions read memory pointed to by their
> > > > -	   first argument.  */
> > > > -	CASE_BUILT_IN_TM_LOAD (1):
> > > > -	CASE_BUILT_IN_TM_LOAD (2):
> > > > -	CASE_BUILT_IN_TM_LOAD (4):
> > > > -	CASE_BUILT_IN_TM_LOAD (8):
> > > > -	CASE_BUILT_IN_TM_LOAD (FLOAT):
> > > > -	CASE_BUILT_IN_TM_LOAD (DOUBLE):
> > > > -	CASE_BUILT_IN_TM_LOAD (LDOUBLE):
> > > > -	CASE_BUILT_IN_TM_LOAD (M64):
> > > > -	CASE_BUILT_IN_TM_LOAD (M128):
> > > > -	CASE_BUILT_IN_TM_LOAD (M256):
> > > > -	case BUILT_IN_TM_LOG:
> > > > -	case BUILT_IN_TM_LOG_1:
> > > > -	case BUILT_IN_TM_LOG_2:
> > > > -	case BUILT_IN_TM_LOG_4:
> > > > -	case BUILT_IN_TM_LOG_8:
> > > > -	case BUILT_IN_TM_LOG_FLOAT:
> > > > -	case BUILT_IN_TM_LOG_DOUBLE:
> > > > -	case BUILT_IN_TM_LOG_LDOUBLE:
> > > > -	case BUILT_IN_TM_LOG_M64:
> > > > -	case BUILT_IN_TM_LOG_M128:
> > > > -	case BUILT_IN_TM_LOG_M256:
> > > > -	  return ptr_deref_may_alias_ref_p_1 (gimple_call_arg (call, 0), ref);
> > > > -
> > > > -	/* These read memory pointed to by the first argument.  */
> > > > -	case BUILT_IN_STRDUP:
> > > > -	case BUILT_IN_STRNDUP:
> > > > -	case BUILT_IN_REALLOC:
> > > > -	  {
> > > > -	    ao_ref dref;
> > > > -	    tree size = NULL_TREE;
> > > > -	    if (gimple_call_num_args (call) == 2)
> > > > -	      size = gimple_call_arg (call, 1);
> > > > -	    ao_ref_init_from_ptr_and_size (&dref,
> > > > -					   gimple_call_arg (call, 0),
> > > > -					   size);
> > > > -	    return refs_may_alias_p_1 (&dref, ref, false);
> > > > -	  }
> > > > -	/* These read memory pointed to by the first argument.  */
> > > > -	case BUILT_IN_INDEX:
> > > > -	case BUILT_IN_STRCHR:
> > > > -	case BUILT_IN_STRRCHR:
> > > > -	  {
> > > > -	    ao_ref dref;
> > > > -	    ao_ref_init_from_ptr_and_size (&dref,
> > > > -					   gimple_call_arg (call, 0),
> > > > -					   NULL_TREE);
> > > > -	    return refs_may_alias_p_1 (&dref, ref, false);
> > > > -	  }
> > > > -	/* These read memory pointed to by the first argument with size
> > > > -	   in the third argument.  */
> > > > -	case BUILT_IN_MEMCHR:
> > > > -	  {
> > > > -	    ao_ref dref;
> > > > -	    ao_ref_init_from_ptr_and_size (&dref,
> > > > -					   gimple_call_arg (call, 0),
> > > > -					   gimple_call_arg (call, 2));
> > > > -	    return refs_may_alias_p_1 (&dref, ref, false);
> > > > -	  }
> > > > -	/* These read memory pointed to by the first and second arguments.  */
> > > > -	case BUILT_IN_STRSTR:
> > > > -	case BUILT_IN_STRPBRK:
> > > > -	  {
> > > > -	    ao_ref dref;
> > > > -	    ao_ref_init_from_ptr_and_size (&dref,
> > > > -					   gimple_call_arg (call, 0),
> > > > -					   NULL_TREE);
> > > > -	    if (refs_may_alias_p_1 (&dref, ref, false))
> > > > -	      return true;
> > > > -	    ao_ref_init_from_ptr_and_size (&dref,
> > > > -					   gimple_call_arg (call, 1),
> > > > -					   NULL_TREE);
> > > > -	    return refs_may_alias_p_1 (&dref, ref, false);
> > > > -	  }
> > > > -
> > > > -	/* The following builtins do not read from memory.  */
> > > > -	case BUILT_IN_FREE:
> > > > -	case BUILT_IN_MALLOC:
> > > > -	case BUILT_IN_POSIX_MEMALIGN:
> > > > -	case BUILT_IN_ALIGNED_ALLOC:
> > > > -	case BUILT_IN_CALLOC:
> > > > -	CASE_BUILT_IN_ALLOCA:
> > > > -	case BUILT_IN_STACK_SAVE:
> > > > -	case BUILT_IN_STACK_RESTORE:
> > > > -	case BUILT_IN_MEMSET:
> > > > -	case BUILT_IN_TM_MEMSET:
> > > > -	case BUILT_IN_MEMSET_CHK:
> > > > -	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_SINCOS:
> > > > -	case BUILT_IN_SINCOSF:
> > > > -	case BUILT_IN_SINCOSL:
> > > > -	case BUILT_IN_ASSUME_ALIGNED:
> > > > -	case BUILT_IN_VA_END:
> > > > +      && gimple_call_builtin_p (call, BUILT_IN_NORMAL)
> > > > +      && (ao_classify_builtin (callee, &info)))
> > > > +    {
> > > > +      if (info.flags & AO_FUNCTION_BARRIER)
> > > > +	return true;
> > > > +      if (info.num_param_reads >= 0)
> > > > +	{
> > > > +	  for (int i = 0; i < info.num_param_reads; i++)
> > > > +	    {
> > > > +	      ao_ref dref;
> > > > +	      tree size = NULL_TREE;
> > > > +
> > > > +	      gcc_checking_assert (info.reads[i].size_param
> > > > +				   != info.reads[i].param);
> > > > +	      if (info.reads[i].size_param != -1)
> > > > +		size = gimple_call_arg (call, info.reads[i].size);
> > > > +	      else if (info.reads[i].size)
> > > > +		size = build_int_cst (size_type_node, info.reads[i].size);
> > > > +	      ao_ref_init_from_ptr_and_size (&dref,
> > > > +					     gimple_call_arg
> > > > +						 (call,
> > > > +						  info.reads[i].param),
> > > > +					     size);
> > > > +	      if (refs_may_alias_p_1 (&dref, ref, tbaa_p))
> > > > +		return true;
> > > > +	    }
> > > >  	  return false;
> > > > -	/* __sync_* builtins and some OpenMP builtins act as threading
> > > > -	   barriers.  */
> > > > -#undef DEF_SYNC_BUILTIN
> > > > -#define DEF_SYNC_BUILTIN(ENUM, NAME, TYPE, ATTRS) case ENUM:
> > > > -#include "sync-builtins.def"
> > > > -#undef DEF_SYNC_BUILTIN
> > > > -	case BUILT_IN_GOMP_ATOMIC_START:
> > > > -	case BUILT_IN_GOMP_ATOMIC_END:
> > > > -	case BUILT_IN_GOMP_BARRIER:
> > > > -	case BUILT_IN_GOMP_BARRIER_CANCEL:
> > > > -	case BUILT_IN_GOMP_TASKWAIT:
> > > > -	case BUILT_IN_GOMP_TASKGROUP_END:
> > > > -	case BUILT_IN_GOMP_CRITICAL_START:
> > > > -	case BUILT_IN_GOMP_CRITICAL_END:
> > > > -	case BUILT_IN_GOMP_CRITICAL_NAME_START:
> > > > -	case BUILT_IN_GOMP_CRITICAL_NAME_END:
> > > > -	case BUILT_IN_GOMP_LOOP_END:
> > > > -	case BUILT_IN_GOMP_LOOP_END_CANCEL:
> > > > -	case BUILT_IN_GOMP_ORDERED_START:
> > > > -	case BUILT_IN_GOMP_ORDERED_END:
> > > > -	case BUILT_IN_GOMP_SECTIONS_END:
> > > > -	case BUILT_IN_GOMP_SECTIONS_END_CANCEL:
> > > > -	case BUILT_IN_GOMP_SINGLE_COPY_START:
> > > > -	case BUILT_IN_GOMP_SINGLE_COPY_END:
> > > > -	  return true;
> > > > -
> > > > -	default:
> > > > -	  /* Fallthru to general call handling.  */;
> > > > -      }
> > > > +	}
> > > > +    }
> > > >  
> > > >    /* Check if base is a global static variable that is not read
> > > >       by the function.  */
> > > > @@ -2961,7 +3280,9 @@ call_may_clobber_ref_p_1 (gcall *call, ao_ref *ref, bool tbaa_p)
> > > >  	  modref_summary *summary = get_modref_function_summary (node);
> > > >  	  if (summary)
> > > >  	    {
> > > > -	      if (!modref_may_conflict (call, summary->stores, ref, tbaa_p))
> > > > +	      if (!modref_may_conflict (call, summary->stores, ref, tbaa_p)
> > > > +		  && (!summary->writes_errno
> > > > +		      || !targetm.ref_may_alias_errno (ref)))
> > > >  		{
> > > >  		  alias_stats.modref_clobber_no_alias++;
> > > >  		  if (dump_file && (dump_flags & TDF_DETAILS))
> > > > @@ -3016,205 +3337,43 @@ call_may_clobber_ref_p_1 (gcall *call, ao_ref *ref, bool tbaa_p)
> > > >        && SSA_NAME_POINTS_TO_READONLY_MEMORY (TREE_OPERAND (base, 0)))
> > > >      return false;
> > > >  
> > > > +  struct ao_function_info info;
> > > >    /* 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.  */
> > > > +     escape points.  */
> > > >    if (callee != NULL_TREE
> > > > -      && gimple_call_builtin_p (call, 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_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:
> > > > -	case BUILT_IN_MEMSET:
> > > > -	case BUILT_IN_TM_MEMSET:
> > > > -	CASE_BUILT_IN_TM_STORE (1):
> > > > -	CASE_BUILT_IN_TM_STORE (2):
> > > > -	CASE_BUILT_IN_TM_STORE (4):
> > > > -	CASE_BUILT_IN_TM_STORE (8):
> > > > -	CASE_BUILT_IN_TM_STORE (FLOAT):
> > > > -	CASE_BUILT_IN_TM_STORE (DOUBLE):
> > > > -	CASE_BUILT_IN_TM_STORE (LDOUBLE):
> > > > -	CASE_BUILT_IN_TM_STORE (M64):
> > > > -	CASE_BUILT_IN_TM_STORE (M128):
> > > > -	CASE_BUILT_IN_TM_STORE (M256):
> > > > -	case BUILT_IN_TM_MEMCPY:
> > > > -	case BUILT_IN_TM_MEMMOVE:
> > > > -	  {
> > > > -	    ao_ref dref;
> > > > -	    tree size = NULL_TREE;
> > > > -	    /* Don't pass in size for strncat, as the maximum size
> > > > -	       is strlen (dest) + n + 1 instead of n, resp.
> > > > -	       n + 1 at dest + strlen (dest), but strlen (dest) isn't
> > > > -	       known.  */
> > > > -	    if (gimple_call_num_args (call) == 3
> > > > -		&& DECL_FUNCTION_CODE (callee) != BUILT_IN_STRNCAT)
> > > > -	      size = gimple_call_arg (call, 2);
> > > > -	    ao_ref_init_from_ptr_and_size (&dref,
> > > > -					   gimple_call_arg (call, 0),
> > > > -					   size);
> > > > -	    return refs_may_alias_p_1 (&dref, ref, false);
> > > > -	  }
> > > > -	case BUILT_IN_STRCPY_CHK:
> > > > -	case BUILT_IN_STRNCPY_CHK:
> > > > -	case BUILT_IN_MEMCPY_CHK:
> > > > -	case BUILT_IN_MEMMOVE_CHK:
> > > > -	case BUILT_IN_MEMPCPY_CHK:
> > > > -	case BUILT_IN_STPCPY_CHK:
> > > > -	case BUILT_IN_STPNCPY_CHK:
> > > > -	case BUILT_IN_STRCAT_CHK:
> > > > -	case BUILT_IN_STRNCAT_CHK:
> > > > -	case BUILT_IN_MEMSET_CHK:
> > > > -	  {
> > > > -	    ao_ref dref;
> > > > -	    tree size = NULL_TREE;
> > > > -	    /* Don't pass in size for __strncat_chk, as the maximum size
> > > > -	       is strlen (dest) + n + 1 instead of n, resp.
> > > > -	       n + 1 at dest + strlen (dest), but strlen (dest) isn't
> > > > -	       known.  */
> > > > -	    if (gimple_call_num_args (call) == 4
> > > > -		&& DECL_FUNCTION_CODE (callee) != BUILT_IN_STRNCAT_CHK)
> > > > -	      size = gimple_call_arg (call, 2);
> > > > -	    ao_ref_init_from_ptr_and_size (&dref,
> > > > -					   gimple_call_arg (call, 0),
> > > > -					   size);
> > > > -	    return refs_may_alias_p_1 (&dref, ref, false);
> > > > -	  }
> > > > -	case BUILT_IN_BCOPY:
> > > > -	  {
> > > > -	    ao_ref dref;
> > > > -	    tree size = gimple_call_arg (call, 2);
> > > > -	    ao_ref_init_from_ptr_and_size (&dref,
> > > > -					   gimple_call_arg (call, 1),
> > > > -					   size);
> > > > -	    return refs_may_alias_p_1 (&dref, ref, false);
> > > > -	  }
> > > > -	/* Allocating memory does not have any side-effects apart from
> > > > -	   being the definition point for the pointer.  */
> > > > -	case BUILT_IN_MALLOC:
> > > > -	case BUILT_IN_ALIGNED_ALLOC:
> > > > -	case BUILT_IN_CALLOC:
> > > > -	case BUILT_IN_STRDUP:
> > > > -	case BUILT_IN_STRNDUP:
> > > > -	  /* Unix98 specifies that errno is set on allocation failure.  */
> > > > -	  if (flag_errno_math
> > > > -	      && targetm.ref_may_alias_errno (ref))
> > > > -	    return true;
> > > > -	  return false;
> > > > -	case BUILT_IN_STACK_SAVE:
> > > > -	CASE_BUILT_IN_ALLOCA:
> > > > -	case BUILT_IN_ASSUME_ALIGNED:
> > > > +      && gimple_call_builtin_p (call, BUILT_IN_NORMAL)
> > > > +      && (ao_classify_builtin (callee, &info)))
> > > > +    {
> > > > +      if (info.flags & AO_FUNCTION_BARRIER)
> > > > +	return true;
> > > > +      if ((info.flags & AO_FUNCTION_ERRNO)
> > > > +	  && flag_errno_math
> > > > +	  && targetm.ref_may_alias_errno (ref))
> > > > +	return true;
> > > > +      if (info.num_param_writes >= 0)
> > > > +	{
> > > > +	  for (int i = 0; i < info.num_param_writes; i++)
> > > > +	    {
> > > > +	      ao_ref dref;
> > > > +	      tree size = NULL_TREE;
> > > > +
> > > > +	      gcc_checking_assert (info.writes[i].size_param
> > > > +				   != info.writes[i].param);
> > > > +	      if (info.writes[i].size_param != -1)
> > > > +		size = gimple_call_arg (call, info.writes[i].size_param);
> > > > +	      else if (info.writes[i].size)
> > > > +		size = build_int_cst (size_type_node, info.writes[i].size);
> > > > +	      ao_ref_init_from_ptr_and_size (&dref,
> > > > +					     gimple_call_arg
> > > > +						 (call,
> > > > +						  info.writes[i].param),
> > > > +					     size);
> > > > +	      if (refs_may_alias_p_1 (&dref, ref, tbaa_p))
> > > > +		return true;
> > > > +	    }
> > > >  	  return false;
> > > > -	/* But posix_memalign stores a pointer into the memory pointed to
> > > > -	   by its first argument.  */
> > > > -	case BUILT_IN_POSIX_MEMALIGN:
> > > > -	  {
> > > > -	    tree ptrptr = gimple_call_arg (call, 0);
> > > > -	    ao_ref dref;
> > > > -	    ao_ref_init_from_ptr_and_size (&dref, ptrptr,
> > > > -					   TYPE_SIZE_UNIT (ptr_type_node));
> > > > -	    return (refs_may_alias_p_1 (&dref, ref, false)
> > > > -		    || (flag_errno_math
> > > > -			&& targetm.ref_may_alias_errno (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.  */
> > > > -	case BUILT_IN_FREE:
> > > > -	case BUILT_IN_VA_END:
> > > > -	  {
> > > > -	    tree ptr = gimple_call_arg (call, 0);
> > > > -	    return ptr_deref_may_alias_ref_p_1 (ptr, ref);
> > > > -	  }
> > > > -	/* Realloc serves both as allocation point and deallocation point.  */
> > > > -	case BUILT_IN_REALLOC:
> > > > -	  {
> > > > -	    tree ptr = gimple_call_arg (call, 0);
> > > > -	    /* Unix98 specifies that errno is set on allocation failure.  */
> > > > -	    return ((flag_errno_math
> > > > -		     && targetm.ref_may_alias_errno (ref))
> > > > -		    || ptr_deref_may_alias_ref_p_1 (ptr, ref));
> > > > -	  }
> > > > -	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:
> > > > -	  {
> > > > -	    tree out = gimple_call_arg (call, 1);
> > > > -	    if (ptr_deref_may_alias_ref_p_1 (out, ref))
> > > > -	      return true;
> > > > -	    if (flag_errno_math)
> > > > -	      break;
> > > > -	    return false;
> > > > -	  }
> > > > -	case BUILT_IN_FREXP:
> > > > -	case BUILT_IN_FREXPF:
> > > > -	case BUILT_IN_FREXPL:
> > > > -	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_1 (out, ref);
> > > > -	  }
> > > > -	case BUILT_IN_REMQUO:
> > > > -	case BUILT_IN_REMQUOF:
> > > > -	case BUILT_IN_REMQUOL:
> > > > -	  {
> > > > -	    tree out = gimple_call_arg (call, 2);
> > > > -	    if (ptr_deref_may_alias_ref_p_1 (out, ref))
> > > > -	      return true;
> > > > -	    if (flag_errno_math)
> > > > -	      break;
> > > > -	    return false;
> > > > -	  }
> > > > -	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);
> > > > -	    return (ptr_deref_may_alias_ref_p_1 (sin, ref)
> > > > -		    || ptr_deref_may_alias_ref_p_1 (cos, ref));
> > > > -	  }
> > > > -	/* __sync_* builtins and some OpenMP builtins act as threading
> > > > -	   barriers.  */
> > > > -#undef DEF_SYNC_BUILTIN
> > > > -#define DEF_SYNC_BUILTIN(ENUM, NAME, TYPE, ATTRS) case ENUM:
> > > > -#include "sync-builtins.def"
> > > > -#undef DEF_SYNC_BUILTIN
> > > > -	case BUILT_IN_GOMP_ATOMIC_START:
> > > > -	case BUILT_IN_GOMP_ATOMIC_END:
> > > > -	case BUILT_IN_GOMP_BARRIER:
> > > > -	case BUILT_IN_GOMP_BARRIER_CANCEL:
> > > > -	case BUILT_IN_GOMP_TASKWAIT:
> > > > -	case BUILT_IN_GOMP_TASKGROUP_END:
> > > > -	case BUILT_IN_GOMP_CRITICAL_START:
> > > > -	case BUILT_IN_GOMP_CRITICAL_END:
> > > > -	case BUILT_IN_GOMP_CRITICAL_NAME_START:
> > > > -	case BUILT_IN_GOMP_CRITICAL_NAME_END:
> > > > -	case BUILT_IN_GOMP_LOOP_END:
> > > > -	case BUILT_IN_GOMP_LOOP_END_CANCEL:
> > > > -	case BUILT_IN_GOMP_ORDERED_START:
> > > > -	case BUILT_IN_GOMP_ORDERED_END:
> > > > -	case BUILT_IN_GOMP_SECTIONS_END:
> > > > -	case BUILT_IN_GOMP_SECTIONS_END_CANCEL:
> > > > -	case BUILT_IN_GOMP_SINGLE_COPY_START:
> > > > -	case BUILT_IN_GOMP_SINGLE_COPY_END:
> > > > -	  return true;
> > > > -	default:
> > > > -	  /* Fallthru to general call handling.  */;
> > > > -      }
> > > > +	}
> > > > +    }
> > > >  
> > > >    /* Check if base is a global static variable that is not written
> > > >       by the function.  */
> > > > 
> > > 
> > > -- 
> > > Richard Biener <rguenther@suse.de>
> > > SUSE Software Solutions Germany GmbH, Maxfeldstrasse 5, 90409 Nuernberg,
> > > Germany; GF: Felix Imend
> > 
> > 
> 
> -- 
> Richard Biener <rguenther@suse.de>
> SUSE Software Solutions Germany GmbH, Maxfeldstrasse 5, 90409 Nuernberg,
> Germany; GF: Felix Imend
Richard Biener Sept. 28, 2020, 10:24 a.m. UTC | #5
On Mon, 28 Sep 2020, Jan Hubicka wrote:

> > 
> > Hmm, no - it expects the gimple_call_use/clobber_set to include
> > actions of the called function itself (const functions none here)
> > but for passed-by-value the loads may be in the call itself
> > which is where it uses gimple_call_arg_flags to skip unused ones.
> > 
> > But note that PTA uses gimple_call_arg_flags to compute
> > the gimple_call_use/clobber_set (but only in IPA mode) and the individual 
> > BUILT_IN_* handlings in tree-ssa-alias.c do what PTA would do
> > here, just directly as alias queries.  Originally I tried adding
> > "fn spec"s to BUILT_IN_* decls but that got out-of-hands ...
> 
> Yep, I was also looking into that, it looks ugly and moreover the
> attributes that depend on flag_math_errno and friends does not really
> work for function speicfic attributes, so it is bug we handle them this
> way.
> 
> Packing this into descriptor string in fnspec rather than descriptor
> sturcture returned on side works for me (and we could add them to thinws
> like C++ toplevel new/delete operator)
> > 
> > For example
> > 
> >         /* All the following functions read memory pointed to by
> >            their second argument.  strcat/strncat additionally
> >            reads memory pointed to by the first argument.  */
> >         case BUILT_IN_STRCAT:
> >         case BUILT_IN_STRNCAT:
> >           {
> >             ao_ref dref;
> >             ao_ref_init_from_ptr_and_size (&dref,
> >                                            gimple_call_arg (call, 0),
> >                                            NULL_TREE);
> >             if (refs_may_alias_p_1 (&dref, ref, false))
> >               return true;
> >           }
> > 
> > would be covered by "1WR" (W also implies read).  So the question
> > would be whether at least parts of your patch could be implemented
> > by making gimple_call_fnspec () return pre-determined fn-specs
> > for BUILT_IN_* (like we do with internal_fn_fnspec).
> 
> One important change would be that we still need to figure out if the
> function has other side effects.  Currently ref_maybe_used_by_call_p_1
> first tries to prove that ref is local and can not be used by the
> function unless it is passed as parameter value and then it looks into
> fnspec if the parameter is used.
> 
> For builtins it constructs tests based on the builtin type and bypasses
> the rest since it knows that all side effects are understood.
> 
> As far as I can tell, fn spec isused only by fortran for library calls,
> so perhaps it would not be too hard to turn fn spec semantics from "some
> properties of parameter handling are known" to "all memory accesses are
> known" or have additional way to indicate this.

Yeah, currently "fn spec" only says we know everything with respect
to a specific parameter but not the whole function.  We'd naturally
say the function is 'const' besides what specified by "fn spec" but
of course we cannot really use 'const' for this how.

> I guess space in return value predictor could be reserved for this, or
> we could have extra flags section at the begining.

Yeah, I think we want pure/const/unknown, so p,c,u with
upper case denoting 'errno' is clobbered (eh...).

> > 
> > >  We would need
> > > to invent how to add info that non pure/const function only access the
> > > argument according to fn spec, add way to represent sizes of accesses
> > > and how to handle errno.
> > 
> > True - fn-spec lacks an ability to specify access size - fortunately
> > it's internal and we could change it ;)  Whether or not sth can clobber
> > errno is sth we eventually need to move to the stmt level anyway
> > (-f[no-]math-errno crossing inline boundary) - bit sad to waste a
> > bit in a gimple call for this though.  OTOH we waste a ton of space
> > in the call_used/call_clobbered members due to bad packing
> > (unsigned int bitfield followed by a pointer to a bitmap).  Eventually
> > we could offload this kind of info from the main stmt.  We could
> > also allocate a fake UID to represent errno (but then the rest of
> > the bits in call_used/call_clobbered have to be precise) - but note
> > call_used/call_clobbered does not transfer during inlining.
> > 
> > So for the access size issue we could blow up fnspec by factor of two,
> > reserving two chars per argument/return value and do
> > 
> >  1.W3R.
> 
> We also have known bytesizes like return values of sincos
> (where the size really matters on the size of type that is known only at
> runtime).
> That can be 3 digits if represented decimally (or two digits hex, but
> it may become too small in future with vector types)

Hmm, we can use Wt for 'formal argument type', so sincos 'double *'
would mean 'double'?  Not sure if that's enough for all cases.

> One option would be make the unit to be the size of pointer pointed to,
> tat would turn it to be 1 in all cases we handle. Then we could blow up
> by 3 and have something like P1 meaning "size is described by parameter
> numer 1" and "10" meaning 10 elements are written by the function.

So for the case we have int * and int n parameter and the size is
n * sizeof (int) you mean?  Do we have this complicated cases for
builtins?  We could also add some escape mechanism (double-ick),
like Wl 'literal' meaning the actual value is appended to the
fn spec.  Thus int foo (int *p, unsigned) writing 54 items to *p
would be ..Wl..54 ... (and L for 4-char literal).  For scaling
by typeof (*p) we could use a-z instead of 1-9 to refer to the
parameter in question.  So yeah, it gets a bit fugly if overloaded
too heavily.

> > for strncat plus add gimple_call_arg_size to access it.  The 2nd
> > slot in return value could host the errno thing (eh).
> > 
> >  .e
> > 
> > for sqrt for example.
> > 
> > Just to repeat again - the info looks too similar to warrant an
> > extra mechanism to record it.
> 
> No problem, just if we figure way to do so :)

Yes indeed.

Richard.

> > 
> > Richard.
> > 
> > > Honza
> > > > 
> > > > > gcc/ChangeLog:
> > > > > 
> > > > > 2020-09-28  Jan Hubicka  <hubicka@ucw.cz>
> > > > > 
> > > > > 	* tree-ssa-alias.c (ao_classify_builtin): New function commonizing
> > > > > 	logic from ...
> > > > > 	(ref_maybe_used_by_call_p_1): ... here.
> > > > > 	(call_may_clobber_ref_p_1): ... and here.
> > > > > 	* tree-ssa-alias.h (enum ao_function_flags): New enum.
> > > > > 	(struct ao_function_info): New structure.
> > > > > 	(ao_classify_builtin): Declare.
> > > > > 
> > > > > diff --git a/gcc/tree-ssa-alias.h b/gcc/tree-ssa-alias.h
> > > > > index 1dd02c0ea62..eecb8da6dd7 100644
> > > > > --- a/gcc/tree-ssa-alias.h
> > > > > +++ b/gcc/tree-ssa-alias.h
> > > > > @@ -108,6 +108,33 @@ ao_ref::max_size_known_p () const
> > > > >    return known_size_p (max_size);
> > > > >  }
> > > > >  
> > > > > +/* Flags used in ao_function_info.  */
> > > > > +
> > > > > +enum ao_function_flags
> > > > > +{
> > > > > +  AO_FUNCTION_BARRIER = 1,
> > > > > +  AO_FUNCTION_ERRNO = 2,
> > > > > +};
> > > > > +
> > > > > +/* Describe side effects relevant for alias analysis of function call to
> > > > > +   DECL.  */
> > > > > +
> > > > > +struct ao_function_info
> > > > > +{
> > > > > +  int num_param_reads;  /* Number of parameters function reads from,
> > > > > +			   -1 if reads are unknown.  */
> > > > > +  struct ao_access_info
> > > > > +    {
> > > > > +      char param; 	/* Index of parameter read/written from.  */
> > > > > +      char size_param;	/* Index of parameter specifying size of the access,
> > > > > +			   -1 if unknown.  */
> > > > > +      char size;	/* Size of access if known, 0 if unknown.  */
> > > > > +    } reads[2];
> > > > > +  int num_param_writes;
> > > > > +  struct ao_access_info writes[2];
> > > > > +  enum ao_function_flags flags;
> > > > > +};
> > > > > +
> > > > >  /* In tree-ssa-alias.c  */
> > > > >  extern void ao_ref_init (ao_ref *, tree);
> > > > >  extern void ao_ref_init_from_ptr_and_size (ao_ref *, tree, tree);
> > > > > @@ -158,6 +185,7 @@ extern void debug (pt_solution *ptr);
> > > > >  extern void dump_points_to_info_for (FILE *, tree);
> > > > >  extern void debug_points_to_info_for (tree);
> > > > >  extern void dump_alias_stats (FILE *);
> > > > > +extern bool ao_classify_builtin (tree callee, ao_function_info *info);
> > > > >  
> > > > >  
> > > > >  /* In tree-ssa-structalias.c  */
> > > > > diff --git a/gcc/tree-ssa-alias.c b/gcc/tree-ssa-alias.c
> > > > > index fe390d4ffbe..c182e7bb39c 100644
> > > > > --- a/gcc/tree-ssa-alias.c
> > > > > +++ b/gcc/tree-ssa-alias.c
> > > > > @@ -2503,6 +2503,507 @@ modref_may_conflict (const gimple *stmt,
> > > > >    return false;
> > > > >  }
> > > > >  
> > > > > +/* If CALLEE has known side effects, fill in INFO and return true.
> > > > > +   See tree-ssa-structalias.c:find_func_aliases
> > > > > +   for the list of builtins we might need to handle here.  */
> > > > > +
> > > > > +bool
> > > > > +ao_classify_builtin (tree callee, ao_function_info *info)
> > > > > +{
> > > > > +  built_in_function code = DECL_FUNCTION_CODE (callee);
> > > > > +
> > > > > +  switch (code)
> > > > > +    {
> > > > > +      /* All the following functions read memory pointed to by
> > > > > +	 their second argument and write memory pointed to by first
> > > > > +	 argument.
> > > > > +	 strcat/strncat additionally reads memory pointed to by the first
> > > > > +	 argument.  */
> > > > > +      case BUILT_IN_STRCAT:
> > > > > +	{
> > > > > +	  const static struct ao_function_info ret_info
> > > > > +	       = {
> > > > > +		    2,				/* num_param_reads.  */
> > > > > +
> > > > > +		    /* Reads and write descriptors are triples containing:
> > > > > +		       - index of parameter read
> > > > > +		       - index of parameter specifying access size
> > > > > +			 (-1 if unknown)
> > > > > +		       - access size in bytes (0 if unkown).  */
> > > > > +
> > > > > +		    {{0, -1, 0}, {1, -1, 0}},	/* Param read.  */
> > > > > +		    1,				/* num_param_writes.  */
> > > > > +		    {{0, -1, 0}},		/* Param written.  */
> > > > > +		    (ao_function_flags)0,	/* flags.  */
> > > > > +		 };
> > > > > +	  *info = ret_info;
> > > > > +	  return true;
> > > > > +	}
> > > > > +      case BUILT_IN_STRNCAT:
> > > > > +	{
> > > > > +	  const static struct ao_function_info ret_info
> > > > > +	       = {
> > > > > +		    2,				/* num_param_reads.  */
> > > > > +		    {{0, -1, 0}, {1, 2, 0}},	/* Param read.  */
> > > > > +		    1,				/* num_param_writes.  */
> > > > > +		    {{0, -1, 0}},		/* Param written.  */
> > > > > +		    (ao_function_flags)0,	/* flags.  */
> > > > > +		 };
> > > > > +	  *info = ret_info;
> > > > > +	  return true;
> > > > > +	}
> > > > > +      case BUILT_IN_STRCPY:
> > > > > +      case BUILT_IN_STPCPY:
> > > > > +	{
> > > > > +	  const static struct ao_function_info ret_info
> > > > > +	       = {
> > > > > +		    1,				/* num_param_reads.  */
> > > > > +		    {{1, -1, 0}},		/* Param read.  */
> > > > > +		    1,				/* num_param_writes.  */
> > > > > +		    {{0, -1, 0}},		/* Param written.  */
> > > > > +		    (ao_function_flags)0,	/* flags.  */
> > > > > +		 };
> > > > > +	  *info = ret_info;
> > > > > +	  return true;
> > > > > +	}
> > > > > +      case BUILT_IN_STRNCPY:
> > > > > +      case BUILT_IN_MEMCPY:
> > > > > +      case BUILT_IN_MEMMOVE:
> > > > > +      case BUILT_IN_MEMPCPY:
> > > > > +      case BUILT_IN_STPNCPY:
> > > > > +      case BUILT_IN_TM_MEMCPY:
> > > > > +      case BUILT_IN_TM_MEMMOVE:
> > > > > +	{
> > > > > +	  const static struct ao_function_info ret_info
> > > > > +	       = {
> > > > > +		    1,				/* num_param_reads.  */
> > > > > +		    {{1, 2, 0}},		/* Param read.  */
> > > > > +		    1,				/* num_param_writes.  */
> > > > > +		    {{0, 2, 0}},		/* Param written.  */
> > > > > +		    (ao_function_flags)0,	/* flags.  */
> > > > > +		 };
> > > > > +	  *info = ret_info;
> > > > > +	  return true;
> > > > > +	}
> > > > > +      case BUILT_IN_STRCAT_CHK:
> > > > > +	{
> > > > > +	  const static struct ao_function_info ret_info
> > > > > +	       = {
> > > > > +		    2,				/* num_param_reads.  */
> > > > > +		    {{0, -1, 0}, {1, -1, 0}},	/* Param read.  */
> > > > > +		    1,				/* num_param_writes.  */
> > > > > +		    {{0, -1, 0}},		/* Param written.  */
> > > > > +		    (ao_function_flags)0,	/* flags.  */
> > > > > +		 };
> > > > > +	  *info = ret_info;
> > > > > +	  return true;
> > > > > +	}
> > > > > +      case BUILT_IN_STRNCAT_CHK:
> > > > > +	{
> > > > > +	  const static struct ao_function_info ret_info
> > > > > +	       = {
> > > > > +		    2,				/* num_param_reads.  */
> > > > > +		    {{0, -1, 0}, {1, 2, 0}},	/* Param read.  */
> > > > > +		    1,				/* num_param_writes.  */
> > > > > +		    {{0, -1, 0}},		/* Param written.  */
> > > > > +		    (ao_function_flags)0,	/* flags.  */
> > > > > +		 };
> > > > > +	  *info = ret_info;
> > > > > +	  return true;
> > > > > +	}
> > > > > +      case BUILT_IN_STRCPY_CHK:
> > > > > +      case BUILT_IN_STPCPY_CHK:
> > > > > +	{
> > > > > +	  const static struct ao_function_info ret_info
> > > > > +	       = {
> > > > > +		    1,				/* num_param_reads.  */
> > > > > +		    {{1, -1, 0}},		/* Param read.  */
> > > > > +		    1,				/* num_param_writes.  */
> > > > > +		    {{0, -1, 0}},		/* Param written.  */
> > > > > +		    (ao_function_flags)0,	/* flags.  */
> > > > > +		 };
> > > > > +	  *info = ret_info;
> > > > > +	  return true;
> > > > > +	}
> > > > > +      case BUILT_IN_STRNCPY_CHK:
> > > > > +      case BUILT_IN_MEMCPY_CHK:
> > > > > +      case BUILT_IN_MEMMOVE_CHK:
> > > > > +      case BUILT_IN_MEMPCPY_CHK:
> > > > > +      case BUILT_IN_STPNCPY_CHK:
> > > > > +	{
> > > > > +	  const static struct ao_function_info ret_info
> > > > > +	       = {
> > > > > +		    1,				/* num_param_reads.  */
> > > > > +		    {{1, 2, 0}},		/* Param read.  */
> > > > > +		    1,				/* num_param_writes.  */
> > > > > +		    {{0, 2, 0}},		/* Param written.  */
> > > > > +		    (ao_function_flags)0,	/* flags.  */
> > > > > +		 };
> > > > > +	  *info = ret_info;
> > > > > +	  return true;
> > > > > +	}
> > > > > +      case BUILT_IN_BCOPY:
> > > > > +	{
> > > > > +	  const static struct ao_function_info ret_info
> > > > > +	       = {
> > > > > +		    1,				/* num_param_reads.  */
> > > > > +		    {{0, 2, 0}},		/* Param read.  */
> > > > > +		    1,				/* num_param_writes.  */
> > > > > +		    {{1, 2, 0}},		/* Param written.  */
> > > > > +		    (ao_function_flags)0,	/* flags.  */
> > > > > +		 };
> > > > > +	  *info = ret_info;
> > > > > +	  return true;
> > > > > +	}
> > > > > +
> > > > > +      /* The following functions read memory pointed to by their
> > > > > +	 first argument.  */
> > > > > +      CASE_BUILT_IN_TM_LOAD (1):
> > > > > +      CASE_BUILT_IN_TM_LOAD (2):
> > > > > +      CASE_BUILT_IN_TM_LOAD (4):
> > > > > +      CASE_BUILT_IN_TM_LOAD (8):
> > > > > +      CASE_BUILT_IN_TM_LOAD (FLOAT):
> > > > > +      CASE_BUILT_IN_TM_LOAD (DOUBLE):
> > > > > +      CASE_BUILT_IN_TM_LOAD (LDOUBLE):
> > > > > +      CASE_BUILT_IN_TM_LOAD (M64):
> > > > > +      CASE_BUILT_IN_TM_LOAD (M128):
> > > > > +      CASE_BUILT_IN_TM_LOAD (M256):
> > > > > +      case BUILT_IN_TM_LOG:
> > > > > +      case BUILT_IN_TM_LOG_1:
> > > > > +      case BUILT_IN_TM_LOG_2:
> > > > > +      case BUILT_IN_TM_LOG_4:
> > > > > +      case BUILT_IN_TM_LOG_8:
> > > > > +      case BUILT_IN_TM_LOG_FLOAT:
> > > > > +      case BUILT_IN_TM_LOG_DOUBLE:
> > > > > +      case BUILT_IN_TM_LOG_LDOUBLE:
> > > > > +      case BUILT_IN_TM_LOG_M64:
> > > > > +      case BUILT_IN_TM_LOG_M128:
> > > > > +      case BUILT_IN_TM_LOG_M256:
> > > > > +
> > > > > +      case BUILT_IN_INDEX:
> > > > > +      case BUILT_IN_STRCHR:
> > > > > +      case BUILT_IN_STRRCHR:
> > > > > +	{
> > > > > +	  const static struct ao_function_info ret_info
> > > > > +	       = {
> > > > > +		    1,				/* num_param_reads.  */
> > > > > +		    /* TODO: For TM builtins size is known.  */
> > > > > +		    {{0, -1, 0}},		/* Param read.  */
> > > > > +		    0,				/* num_param_writes.  */
> > > > > +		    {},				/* Param written.  */
> > > > > +		    (ao_function_flags)0,	/* flags.  */
> > > > > +		 };
> > > > > +	  *info = ret_info;
> > > > > +	  return true;
> > > > > +	}
> > > > > +
> > > > > +      /* These read memory pointed to by the first argument.
> > > > > +	 Allocating memory does not have any side-effects apart from
> > > > > +	 being the definition point for the pointer.
> > > > > +	 Unix98 specifies that errno is set on allocation failure.  */
> > > > > +      case BUILT_IN_STRDUP:
> > > > > +	{
> > > > > +	  const static struct ao_function_info ret_info
> > > > > +	       = {
> > > > > +		    1,				/* num_param_reads.  */
> > > > > +		    {{0, -1, 0}},		/* Param read.  */
> > > > > +		    0,				/* num_param_writes.  */
> > > > > +		    {},				/* Param written.  */
> > > > > +		    AO_FUNCTION_ERRNO,		/* flags.  */
> > > > > +		 };
> > > > > +	  *info = ret_info;
> > > > > +	  return true;
> > > > > +	}
> > > > > +      case BUILT_IN_STRNDUP:
> > > > > +	{
> > > > > +	  const static struct ao_function_info ret_info
> > > > > +	       = {
> > > > > +		    1,				/* num_param_reads.  */
> > > > > +		    {{0, 1, 0}},		/* Param read.  */
> > > > > +		    0,				/* num_param_writes.  */
> > > > > +		    {},				/* Param written.  */
> > > > > +		    AO_FUNCTION_ERRNO,		/* flags.  */
> > > > > +		 };
> > > > > +	  *info = ret_info;
> > > > > +	  return true;
> > > > > +	}
> > > > > +      /* Allocating memory does not have any side-effects apart from
> > > > > +	 being the definition point for the pointer.  */
> > > > > +      case BUILT_IN_MALLOC:
> > > > > +      case BUILT_IN_ALIGNED_ALLOC:
> > > > > +      case BUILT_IN_CALLOC:
> > > > > +	{
> > > > > +	  const static struct ao_function_info ret_info
> > > > > +	       = {
> > > > > +		    0,				/* num_param_reads.  */
> > > > > +		    {},				/* Param read.  */
> > > > > +		    0,				/* num_param_writes.  */
> > > > > +		    {},				/* Param written.  */
> > > > > +		    AO_FUNCTION_ERRNO,		/* flags.  */
> > > > > +		 };
> > > > > +	  *info = ret_info;
> > > > > +	  return true;
> > > > > +	}
> > > > > +      /* These read memory pointed to by the first argument with size
> > > > > +	 in the third argument.  */
> > > > > +      case BUILT_IN_MEMCHR:
> > > > > +	{
> > > > > +	  const static struct ao_function_info ret_info
> > > > > +	       = {
> > > > > +		    1,				/* num_param_reads.  */
> > > > > +		    {{0, 2, 0}},		/* Param read.  */
> > > > > +		    0,				/* num_param_writes.  */
> > > > > +		    {},				/* Param written.  */
> > > > > +		    (ao_function_flags)0,	/* flags.  */
> > > > > +		 };
> > > > > +	  *info = ret_info;
> > > > > +	  return true;
> > > > > +	}
> > > > > +      /* These read memory pointed to by the first and second arguments.  */
> > > > > +      case BUILT_IN_STRSTR:
> > > > > +      case BUILT_IN_STRPBRK:
> > > > > +	{
> > > > > +	  static struct ao_function_info ret_info
> > > > > +	       = {
> > > > > +		    2,				/* num_param_reads.  */
> > > > > +		    {{0, -1, 0}, {1, -1, 0}},	/* Param read.  */
> > > > > +		    0,				/* num_param_writes.  */
> > > > > +		    {},				/* Param written.  */
> > > > > +		    (ao_function_flags)0,	/* flags.  */
> > > > > +		 };
> > > > > +	  *info = ret_info;
> > > > > +	  return true;
> > > > > +	}
> > > > > +      /* Freeing memory kills the pointed-to memory.  More importantly
> > > > > +	 the call has to serve as a barrier for moving loads and stores
> > > > > +	 across it.  */
> > > > > +      case BUILT_IN_FREE:
> > > > > +      case BUILT_IN_VA_END:
> > > > > +	{
> > > > > +	  const static struct ao_function_info ret_info
> > > > > +	       = {
> > > > > +		    0,				/* num_param_reads.  */
> > > > > +		    {},				/* Param read.  */
> > > > > +		    1,				/* num_param_writes.  */
> > > > > +		    {{0, -1, 0}},		/* Param written.  */
> > > > > +		    (ao_function_flags)0,	/* flags.  */
> > > > > +		 };
> > > > > +	  *info = ret_info;
> > > > > +	  return true;
> > > > > +	}
> > > > > +      /* Realloc serves both as allocation point and deallocation point.  */
> > > > > +      case BUILT_IN_REALLOC:
> > > > > +	{
> > > > > +	  const static struct ao_function_info ret_info
> > > > > +	       = {
> > > > > +		    1,				/* num_param_reads.  */
> > > > > +		    {{0, 1, 0}},		/* Param read.  */
> > > > > +		    0,				/* num_param_writes.  */
> > > > > +		    {{0, -1, 0}},		/* Param written.  */
> > > > > +		    AO_FUNCTION_ERRNO,		/* flags.  */
> > > > > +		 };
> > > > > +	  *info = ret_info;
> > > > > +	  return true;
> > > > > +	}
> > > > > +      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:
> > > > > +	{
> > > > > +	  const static struct ao_function_info ret_info
> > > > > +	       = {
> > > > > +		    0,				/* num_param_reads.  */
> > > > > +		    {},				/* Param read.  */
> > > > > +		    1,				/* num_param_writes.  */
> > > > > +		    {{1, -1, 0}},		/* Param written.  */
> > > > > +		    AO_FUNCTION_ERRNO,		/* flags.  */
> > > > > +		 };
> > > > > +	  *info = ret_info;
> > > > > +	  return true;
> > > > > +	}
> > > > > +      case BUILT_IN_FREXP:
> > > > > +      case BUILT_IN_FREXPF:
> > > > > +      case BUILT_IN_FREXPL:
> > > > > +      case BUILT_IN_MODF:
> > > > > +      case BUILT_IN_MODFF:
> > > > > +      case BUILT_IN_MODFL:
> > > > > +	{
> > > > > +	  const static struct ao_function_info ret_info
> > > > > +	       = {
> > > > > +		    0,				/* num_param_reads.  */
> > > > > +		    {},				/* Param read.  */
> > > > > +		    1,				/* num_param_writes.  */
> > > > > +		    {{1, -1, 0}},		/* Param written.  */
> > > > > +		    (ao_function_flags)0,	/* flags.  */
> > > > > +		 };
> > > > > +	  *info = ret_info;
> > > > > +	  return true;
> > > > > +	}
> > > > > +      case BUILT_IN_REMQUO:
> > > > > +      case BUILT_IN_REMQUOF:
> > > > > +      case BUILT_IN_REMQUOL:
> > > > > +	{
> > > > > +	  const static struct ao_function_info ret_info
> > > > > +	       = {
> > > > > +		    0,				/* num_param_reads.  */
> > > > > +		    {},				/* Param read.  */
> > > > > +		    1,				/* num_param_writes.  */
> > > > > +		    {{2, -1, 0}},		/* Param written.  */
> > > > > +		    (ao_function_flags)0,	/* flags.  */
> > > > > +		 };
> > > > > +	  *info = ret_info;
> > > > > +	  return true;
> > > > > +	}
> > > > > +      case BUILT_IN_SINCOS:
> > > > > +      case BUILT_IN_SINCOSF:
> > > > > +      case BUILT_IN_SINCOSL:
> > > > > +	{
> > > > > +	  static struct ao_function_info ret_info
> > > > > +	       = {
> > > > > +		    0,				/* num_param_reads.  */
> > > > > +		    {},				/* Param read.  */
> > > > > +		    1,				/* num_param_writes.  */
> > > > > +		    {{1, -1, 0}, {2, -1, 0}},	/* Param written.  */
> > > > > +		    (ao_function_flags)0,	/* flags.  */
> > > > > +		 };
> > > > > +	  tree type = float_ptr_type_node;
> > > > > +	  if (code == BUILT_IN_SINCOS)
> > > > > +	    type = double_ptr_type_node;
> > > > > +	  else
> > > > > +	    type = long_double_ptr_type_node;
> > > > > +	  ret_info.writes[0].size = ret_info.writes[1].size
> > > > > +		 = tree_to_uhwi (TYPE_SIZE_UNIT (type));
> > > > > +	  *info = ret_info;
> > > > > +	  return true;
> > > > > +	}
> > > > > +      case BUILT_IN_MEMSET:
> > > > > +      case BUILT_IN_MEMSET_CHK:
> > > > > +      case BUILT_IN_TM_MEMSET:
> > > > > +	{
> > > > > +	  const static struct ao_function_info ret_info
> > > > > +	       = {
> > > > > +		    0,				/* num_param_reads.  */
> > > > > +		    {},				/* Param read.  */
> > > > > +		    1,				/* num_param_writes.  */
> > > > > +		    {0, 2, 0},			/* Param written.  */
> > > > > +		    (ao_function_flags)0,	/* flags.  */
> > > > > +		 };
> > > > > +	  *info = ret_info;
> > > > > +	  return true;
> > > > > +	}
> > > > > +      CASE_BUILT_IN_TM_STORE (1):
> > > > > +      CASE_BUILT_IN_TM_STORE (2):
> > > > > +      CASE_BUILT_IN_TM_STORE (4):
> > > > > +      CASE_BUILT_IN_TM_STORE (8):
> > > > > +      CASE_BUILT_IN_TM_STORE (FLOAT):
> > > > > +      CASE_BUILT_IN_TM_STORE (DOUBLE):
> > > > > +      CASE_BUILT_IN_TM_STORE (LDOUBLE):
> > > > > +      CASE_BUILT_IN_TM_STORE (M64):
> > > > > +      CASE_BUILT_IN_TM_STORE (M128):
> > > > > +      CASE_BUILT_IN_TM_STORE (M256):
> > > > > +	{
> > > > > +	  const static struct ao_function_info ret_info
> > > > > +	       = {
> > > > > +		    0,				/* num_param_reads.  */
> > > > > +		    {},				/* Param read.  */
> > > > > +		    1,				/* num_param_writes.  */
> > > > > +		    /* TODO: Size is known.  */
> > > > > +		    {0, -1, 0},			/* Param written.  */
> > > > > +		    (ao_function_flags)0,	/* flags.  */
> > > > > +		 };
> > > > > +	  *info = ret_info;
> > > > > +	  return true;
> > > > > +	}
> > > > > +      case BUILT_IN_STACK_SAVE:
> > > > > +      CASE_BUILT_IN_ALLOCA:
> > > > > +      case BUILT_IN_ASSUME_ALIGNED:
> > > > > +	{
> > > > > +	  const static struct ao_function_info ret_info
> > > > > +	       = {
> > > > > +		    0,				/* num_param_reads.  */
> > > > > +		    {},				/* Param read.  */
> > > > > +		    0,				/* num_param_writes.  */
> > > > > +		    {},				/* Param written.  */
> > > > > +		    (ao_function_flags)0,	/* flags.  */
> > > > > +		 };
> > > > > +	  *info = ret_info;
> > > > > +	  return true;
> > > > > +	}
> > > > > +      /* But posix_memalign stores a pointer into the memory pointed to
> > > > > +	 by its first argument.  */
> > > > > +      case BUILT_IN_POSIX_MEMALIGN:
> > > > > +	{
> > > > > +	  static struct ao_function_info ret_info
> > > > > +	       = {
> > > > > +		    0,				/* num_param_reads.  */
> > > > > +		    {},				/* Param read.  */
> > > > > +		    0,				/* num_param_writes.  */
> > > > > +		    {{0, -1, 0}},		/* Param written.  */
> > > > > +		    AO_FUNCTION_ERRNO,		/* flags.  */
> > > > > +		 };
> > > > > +	  ret_info.writes[0].size
> > > > > +		 = tree_to_uhwi (TYPE_SIZE_UNIT (ptr_type_node));
> > > > > +	  *info = ret_info;
> > > > > +	  return true;
> > > > > +	}
> > > > > +      /* The following builtins do not read from memory.  */
> > > > > +      case BUILT_IN_STACK_RESTORE:
> > > > > +	{
> > > > > +	  const static struct ao_function_info ret_info
> > > > > +	       = {
> > > > > +		    0,				/* num_param_reads.  */
> > > > > +		    {},				/* Param read.  */
> > > > > +		    0,				/* num_param_writes.  */
> > > > > +		    {},				/* Param written.  */
> > > > > +		    (ao_function_flags)0,	/* flags.  */
> > > > > +		 };
> > > > > +	  *info = ret_info;
> > > > > +	  return true;
> > > > > +	}
> > > > > +      /* __sync_* builtins and some OpenMP builtins act as threading
> > > > > +	 barriers.  */
> > > > > +#undef DEF_SYNC_BUILTIN
> > > > > +#define DEF_SYNC_BUILTIN(ENUM, NAME, TYPE, ATTRS) case ENUM:
> > > > > +#include "sync-builtins.def"
> > > > > +#undef DEF_SYNC_BUILTIN
> > > > > +      case BUILT_IN_GOMP_ATOMIC_START:
> > > > > +      case BUILT_IN_GOMP_ATOMIC_END:
> > > > > +      case BUILT_IN_GOMP_BARRIER:
> > > > > +      case BUILT_IN_GOMP_BARRIER_CANCEL:
> > > > > +      case BUILT_IN_GOMP_TASKWAIT:
> > > > > +      case BUILT_IN_GOMP_TASKGROUP_END:
> > > > > +      case BUILT_IN_GOMP_CRITICAL_START:
> > > > > +      case BUILT_IN_GOMP_CRITICAL_END:
> > > > > +      case BUILT_IN_GOMP_CRITICAL_NAME_START:
> > > > > +      case BUILT_IN_GOMP_CRITICAL_NAME_END:
> > > > > +      case BUILT_IN_GOMP_LOOP_END:
> > > > > +      case BUILT_IN_GOMP_LOOP_END_CANCEL:
> > > > > +      case BUILT_IN_GOMP_ORDERED_START:
> > > > > +      case BUILT_IN_GOMP_ORDERED_END:
> > > > > +      case BUILT_IN_GOMP_SECTIONS_END:
> > > > > +      case BUILT_IN_GOMP_SECTIONS_END_CANCEL:
> > > > > +      case BUILT_IN_GOMP_SINGLE_COPY_START:
> > > > > +      case BUILT_IN_GOMP_SINGLE_COPY_END:
> > > > > +	{
> > > > > +	  const static struct ao_function_info ret_info
> > > > > +	       = {
> > > > > +		    -1,				/* num_param_reads.  */
> > > > > +		    {},				/* Param read.  */
> > > > > +		    -1,				/* num_param_writes.  */
> > > > > +		    {},				/* Param written.  */
> > > > > +		    AO_FUNCTION_BARRIER,	/* flags.  */
> > > > > +		 };
> > > > > +	  *info = ret_info;
> > > > > +	  return true;
> > > > > +	}
> > > > > +
> > > > > +      default:
> > > > > +	return false;
> > > > > +    }
> > > > > +}
> > > > > +
> > > > >  /* If the call CALL may use the memory reference REF return true,
> > > > >     otherwise return false.  */
> > > > >  
> > > > > @@ -2574,219 +3075,37 @@ ref_maybe_used_by_call_p_1 (gcall *call, ao_ref *ref, bool tbaa_p)
> > > > >    /* 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.  */
> > > > > +  struct ao_function_info info;
> > > > >    if (callee != NULL_TREE
> > > > > -      && gimple_call_builtin_p (call, BUILT_IN_NORMAL))
> > > > > -    switch (DECL_FUNCTION_CODE (callee))
> > > > > -      {
> > > > > -	/* All the following functions read memory pointed to by
> > > > > -	   their second argument.  strcat/strncat additionally
> > > > > -	   reads memory pointed to by the first argument.  */
> > > > > -	case BUILT_IN_STRCAT:
> > > > > -	case BUILT_IN_STRNCAT:
> > > > > -	  {
> > > > > -	    ao_ref dref;
> > > > > -	    ao_ref_init_from_ptr_and_size (&dref,
> > > > > -					   gimple_call_arg (call, 0),
> > > > > -					   NULL_TREE);
> > > > > -	    if (refs_may_alias_p_1 (&dref, ref, false))
> > > > > -	      return true;
> > > > > -	  }
> > > > > -	  /* FALLTHRU */
> > > > > -	case BUILT_IN_STRCPY:
> > > > > -	case BUILT_IN_STRNCPY:
> > > > > -	case BUILT_IN_MEMCPY:
> > > > > -	case BUILT_IN_MEMMOVE:
> > > > > -	case BUILT_IN_MEMPCPY:
> > > > > -	case BUILT_IN_STPCPY:
> > > > > -	case BUILT_IN_STPNCPY:
> > > > > -	case BUILT_IN_TM_MEMCPY:
> > > > > -	case BUILT_IN_TM_MEMMOVE:
> > > > > -	  {
> > > > > -	    ao_ref dref;
> > > > > -	    tree size = NULL_TREE;
> > > > > -	    if (gimple_call_num_args (call) == 3)
> > > > > -	      size = gimple_call_arg (call, 2);
> > > > > -	    ao_ref_init_from_ptr_and_size (&dref,
> > > > > -					   gimple_call_arg (call, 1),
> > > > > -					   size);
> > > > > -	    return refs_may_alias_p_1 (&dref, ref, false);
> > > > > -	  }
> > > > > -	case BUILT_IN_STRCAT_CHK:
> > > > > -	case BUILT_IN_STRNCAT_CHK:
> > > > > -	  {
> > > > > -	    ao_ref dref;
> > > > > -	    ao_ref_init_from_ptr_and_size (&dref,
> > > > > -					   gimple_call_arg (call, 0),
> > > > > -					   NULL_TREE);
> > > > > -	    if (refs_may_alias_p_1 (&dref, ref, false))
> > > > > -	      return true;
> > > > > -	  }
> > > > > -	  /* FALLTHRU */
> > > > > -	case BUILT_IN_STRCPY_CHK:
> > > > > -	case BUILT_IN_STRNCPY_CHK:
> > > > > -	case BUILT_IN_MEMCPY_CHK:
> > > > > -	case BUILT_IN_MEMMOVE_CHK:
> > > > > -	case BUILT_IN_MEMPCPY_CHK:
> > > > > -	case BUILT_IN_STPCPY_CHK:
> > > > > -	case BUILT_IN_STPNCPY_CHK:
> > > > > -	  {
> > > > > -	    ao_ref dref;
> > > > > -	    tree size = NULL_TREE;
> > > > > -	    if (gimple_call_num_args (call) == 4)
> > > > > -	      size = gimple_call_arg (call, 2);
> > > > > -	    ao_ref_init_from_ptr_and_size (&dref,
> > > > > -					   gimple_call_arg (call, 1),
> > > > > -					   size);
> > > > > -	    return refs_may_alias_p_1 (&dref, ref, false);
> > > > > -	  }
> > > > > -	case BUILT_IN_BCOPY:
> > > > > -	  {
> > > > > -	    ao_ref dref;
> > > > > -	    tree size = gimple_call_arg (call, 2);
> > > > > -	    ao_ref_init_from_ptr_and_size (&dref,
> > > > > -					   gimple_call_arg (call, 0),
> > > > > -					   size);
> > > > > -	    return refs_may_alias_p_1 (&dref, ref, false);
> > > > > -	  }
> > > > > -
> > > > > -	/* The following functions read memory pointed to by their
> > > > > -	   first argument.  */
> > > > > -	CASE_BUILT_IN_TM_LOAD (1):
> > > > > -	CASE_BUILT_IN_TM_LOAD (2):
> > > > > -	CASE_BUILT_IN_TM_LOAD (4):
> > > > > -	CASE_BUILT_IN_TM_LOAD (8):
> > > > > -	CASE_BUILT_IN_TM_LOAD (FLOAT):
> > > > > -	CASE_BUILT_IN_TM_LOAD (DOUBLE):
> > > > > -	CASE_BUILT_IN_TM_LOAD (LDOUBLE):
> > > > > -	CASE_BUILT_IN_TM_LOAD (M64):
> > > > > -	CASE_BUILT_IN_TM_LOAD (M128):
> > > > > -	CASE_BUILT_IN_TM_LOAD (M256):
> > > > > -	case BUILT_IN_TM_LOG:
> > > > > -	case BUILT_IN_TM_LOG_1:
> > > > > -	case BUILT_IN_TM_LOG_2:
> > > > > -	case BUILT_IN_TM_LOG_4:
> > > > > -	case BUILT_IN_TM_LOG_8:
> > > > > -	case BUILT_IN_TM_LOG_FLOAT:
> > > > > -	case BUILT_IN_TM_LOG_DOUBLE:
> > > > > -	case BUILT_IN_TM_LOG_LDOUBLE:
> > > > > -	case BUILT_IN_TM_LOG_M64:
> > > > > -	case BUILT_IN_TM_LOG_M128:
> > > > > -	case BUILT_IN_TM_LOG_M256:
> > > > > -	  return ptr_deref_may_alias_ref_p_1 (gimple_call_arg (call, 0), ref);
> > > > > -
> > > > > -	/* These read memory pointed to by the first argument.  */
> > > > > -	case BUILT_IN_STRDUP:
> > > > > -	case BUILT_IN_STRNDUP:
> > > > > -	case BUILT_IN_REALLOC:
> > > > > -	  {
> > > > > -	    ao_ref dref;
> > > > > -	    tree size = NULL_TREE;
> > > > > -	    if (gimple_call_num_args (call) == 2)
> > > > > -	      size = gimple_call_arg (call, 1);
> > > > > -	    ao_ref_init_from_ptr_and_size (&dref,
> > > > > -					   gimple_call_arg (call, 0),
> > > > > -					   size);
> > > > > -	    return refs_may_alias_p_1 (&dref, ref, false);
> > > > > -	  }
> > > > > -	/* These read memory pointed to by the first argument.  */
> > > > > -	case BUILT_IN_INDEX:
> > > > > -	case BUILT_IN_STRCHR:
> > > > > -	case BUILT_IN_STRRCHR:
> > > > > -	  {
> > > > > -	    ao_ref dref;
> > > > > -	    ao_ref_init_from_ptr_and_size (&dref,
> > > > > -					   gimple_call_arg (call, 0),
> > > > > -					   NULL_TREE);
> > > > > -	    return refs_may_alias_p_1 (&dref, ref, false);
> > > > > -	  }
> > > > > -	/* These read memory pointed to by the first argument with size
> > > > > -	   in the third argument.  */
> > > > > -	case BUILT_IN_MEMCHR:
> > > > > -	  {
> > > > > -	    ao_ref dref;
> > > > > -	    ao_ref_init_from_ptr_and_size (&dref,
> > > > > -					   gimple_call_arg (call, 0),
> > > > > -					   gimple_call_arg (call, 2));
> > > > > -	    return refs_may_alias_p_1 (&dref, ref, false);
> > > > > -	  }
> > > > > -	/* These read memory pointed to by the first and second arguments.  */
> > > > > -	case BUILT_IN_STRSTR:
> > > > > -	case BUILT_IN_STRPBRK:
> > > > > -	  {
> > > > > -	    ao_ref dref;
> > > > > -	    ao_ref_init_from_ptr_and_size (&dref,
> > > > > -					   gimple_call_arg (call, 0),
> > > > > -					   NULL_TREE);
> > > > > -	    if (refs_may_alias_p_1 (&dref, ref, false))
> > > > > -	      return true;
> > > > > -	    ao_ref_init_from_ptr_and_size (&dref,
> > > > > -					   gimple_call_arg (call, 1),
> > > > > -					   NULL_TREE);
> > > > > -	    return refs_may_alias_p_1 (&dref, ref, false);
> > > > > -	  }
> > > > > -
> > > > > -	/* The following builtins do not read from memory.  */
> > > > > -	case BUILT_IN_FREE:
> > > > > -	case BUILT_IN_MALLOC:
> > > > > -	case BUILT_IN_POSIX_MEMALIGN:
> > > > > -	case BUILT_IN_ALIGNED_ALLOC:
> > > > > -	case BUILT_IN_CALLOC:
> > > > > -	CASE_BUILT_IN_ALLOCA:
> > > > > -	case BUILT_IN_STACK_SAVE:
> > > > > -	case BUILT_IN_STACK_RESTORE:
> > > > > -	case BUILT_IN_MEMSET:
> > > > > -	case BUILT_IN_TM_MEMSET:
> > > > > -	case BUILT_IN_MEMSET_CHK:
> > > > > -	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_SINCOS:
> > > > > -	case BUILT_IN_SINCOSF:
> > > > > -	case BUILT_IN_SINCOSL:
> > > > > -	case BUILT_IN_ASSUME_ALIGNED:
> > > > > -	case BUILT_IN_VA_END:
> > > > > +      && gimple_call_builtin_p (call, BUILT_IN_NORMAL)
> > > > > +      && (ao_classify_builtin (callee, &info)))
> > > > > +    {
> > > > > +      if (info.flags & AO_FUNCTION_BARRIER)
> > > > > +	return true;
> > > > > +      if (info.num_param_reads >= 0)
> > > > > +	{
> > > > > +	  for (int i = 0; i < info.num_param_reads; i++)
> > > > > +	    {
> > > > > +	      ao_ref dref;
> > > > > +	      tree size = NULL_TREE;
> > > > > +
> > > > > +	      gcc_checking_assert (info.reads[i].size_param
> > > > > +				   != info.reads[i].param);
> > > > > +	      if (info.reads[i].size_param != -1)
> > > > > +		size = gimple_call_arg (call, info.reads[i].size);
> > > > > +	      else if (info.reads[i].size)
> > > > > +		size = build_int_cst (size_type_node, info.reads[i].size);
> > > > > +	      ao_ref_init_from_ptr_and_size (&dref,
> > > > > +					     gimple_call_arg
> > > > > +						 (call,
> > > > > +						  info.reads[i].param),
> > > > > +					     size);
> > > > > +	      if (refs_may_alias_p_1 (&dref, ref, tbaa_p))
> > > > > +		return true;
> > > > > +	    }
> > > > >  	  return false;
> > > > > -	/* __sync_* builtins and some OpenMP builtins act as threading
> > > > > -	   barriers.  */
> > > > > -#undef DEF_SYNC_BUILTIN
> > > > > -#define DEF_SYNC_BUILTIN(ENUM, NAME, TYPE, ATTRS) case ENUM:
> > > > > -#include "sync-builtins.def"
> > > > > -#undef DEF_SYNC_BUILTIN
> > > > > -	case BUILT_IN_GOMP_ATOMIC_START:
> > > > > -	case BUILT_IN_GOMP_ATOMIC_END:
> > > > > -	case BUILT_IN_GOMP_BARRIER:
> > > > > -	case BUILT_IN_GOMP_BARRIER_CANCEL:
> > > > > -	case BUILT_IN_GOMP_TASKWAIT:
> > > > > -	case BUILT_IN_GOMP_TASKGROUP_END:
> > > > > -	case BUILT_IN_GOMP_CRITICAL_START:
> > > > > -	case BUILT_IN_GOMP_CRITICAL_END:
> > > > > -	case BUILT_IN_GOMP_CRITICAL_NAME_START:
> > > > > -	case BUILT_IN_GOMP_CRITICAL_NAME_END:
> > > > > -	case BUILT_IN_GOMP_LOOP_END:
> > > > > -	case BUILT_IN_GOMP_LOOP_END_CANCEL:
> > > > > -	case BUILT_IN_GOMP_ORDERED_START:
> > > > > -	case BUILT_IN_GOMP_ORDERED_END:
> > > > > -	case BUILT_IN_GOMP_SECTIONS_END:
> > > > > -	case BUILT_IN_GOMP_SECTIONS_END_CANCEL:
> > > > > -	case BUILT_IN_GOMP_SINGLE_COPY_START:
> > > > > -	case BUILT_IN_GOMP_SINGLE_COPY_END:
> > > > > -	  return true;
> > > > > -
> > > > > -	default:
> > > > > -	  /* Fallthru to general call handling.  */;
> > > > > -      }
> > > > > +	}
> > > > > +    }
> > > > >  
> > > > >    /* Check if base is a global static variable that is not read
> > > > >       by the function.  */
> > > > > @@ -2961,7 +3280,9 @@ call_may_clobber_ref_p_1 (gcall *call, ao_ref *ref, bool tbaa_p)
> > > > >  	  modref_summary *summary = get_modref_function_summary (node);
> > > > >  	  if (summary)
> > > > >  	    {
> > > > > -	      if (!modref_may_conflict (call, summary->stores, ref, tbaa_p))
> > > > > +	      if (!modref_may_conflict (call, summary->stores, ref, tbaa_p)
> > > > > +		  && (!summary->writes_errno
> > > > > +		      || !targetm.ref_may_alias_errno (ref)))
> > > > >  		{
> > > > >  		  alias_stats.modref_clobber_no_alias++;
> > > > >  		  if (dump_file && (dump_flags & TDF_DETAILS))
> > > > > @@ -3016,205 +3337,43 @@ call_may_clobber_ref_p_1 (gcall *call, ao_ref *ref, bool tbaa_p)
> > > > >        && SSA_NAME_POINTS_TO_READONLY_MEMORY (TREE_OPERAND (base, 0)))
> > > > >      return false;
> > > > >  
> > > > > +  struct ao_function_info info;
> > > > >    /* 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.  */
> > > > > +     escape points.  */
> > > > >    if (callee != NULL_TREE
> > > > > -      && gimple_call_builtin_p (call, 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_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:
> > > > > -	case BUILT_IN_MEMSET:
> > > > > -	case BUILT_IN_TM_MEMSET:
> > > > > -	CASE_BUILT_IN_TM_STORE (1):
> > > > > -	CASE_BUILT_IN_TM_STORE (2):
> > > > > -	CASE_BUILT_IN_TM_STORE (4):
> > > > > -	CASE_BUILT_IN_TM_STORE (8):
> > > > > -	CASE_BUILT_IN_TM_STORE (FLOAT):
> > > > > -	CASE_BUILT_IN_TM_STORE (DOUBLE):
> > > > > -	CASE_BUILT_IN_TM_STORE (LDOUBLE):
> > > > > -	CASE_BUILT_IN_TM_STORE (M64):
> > > > > -	CASE_BUILT_IN_TM_STORE (M128):
> > > > > -	CASE_BUILT_IN_TM_STORE (M256):
> > > > > -	case BUILT_IN_TM_MEMCPY:
> > > > > -	case BUILT_IN_TM_MEMMOVE:
> > > > > -	  {
> > > > > -	    ao_ref dref;
> > > > > -	    tree size = NULL_TREE;
> > > > > -	    /* Don't pass in size for strncat, as the maximum size
> > > > > -	       is strlen (dest) + n + 1 instead of n, resp.
> > > > > -	       n + 1 at dest + strlen (dest), but strlen (dest) isn't
> > > > > -	       known.  */
> > > > > -	    if (gimple_call_num_args (call) == 3
> > > > > -		&& DECL_FUNCTION_CODE (callee) != BUILT_IN_STRNCAT)
> > > > > -	      size = gimple_call_arg (call, 2);
> > > > > -	    ao_ref_init_from_ptr_and_size (&dref,
> > > > > -					   gimple_call_arg (call, 0),
> > > > > -					   size);
> > > > > -	    return refs_may_alias_p_1 (&dref, ref, false);
> > > > > -	  }
> > > > > -	case BUILT_IN_STRCPY_CHK:
> > > > > -	case BUILT_IN_STRNCPY_CHK:
> > > > > -	case BUILT_IN_MEMCPY_CHK:
> > > > > -	case BUILT_IN_MEMMOVE_CHK:
> > > > > -	case BUILT_IN_MEMPCPY_CHK:
> > > > > -	case BUILT_IN_STPCPY_CHK:
> > > > > -	case BUILT_IN_STPNCPY_CHK:
> > > > > -	case BUILT_IN_STRCAT_CHK:
> > > > > -	case BUILT_IN_STRNCAT_CHK:
> > > > > -	case BUILT_IN_MEMSET_CHK:
> > > > > -	  {
> > > > > -	    ao_ref dref;
> > > > > -	    tree size = NULL_TREE;
> > > > > -	    /* Don't pass in size for __strncat_chk, as the maximum size
> > > > > -	       is strlen (dest) + n + 1 instead of n, resp.
> > > > > -	       n + 1 at dest + strlen (dest), but strlen (dest) isn't
> > > > > -	       known.  */
> > > > > -	    if (gimple_call_num_args (call) == 4
> > > > > -		&& DECL_FUNCTION_CODE (callee) != BUILT_IN_STRNCAT_CHK)
> > > > > -	      size = gimple_call_arg (call, 2);
> > > > > -	    ao_ref_init_from_ptr_and_size (&dref,
> > > > > -					   gimple_call_arg (call, 0),
> > > > > -					   size);
> > > > > -	    return refs_may_alias_p_1 (&dref, ref, false);
> > > > > -	  }
> > > > > -	case BUILT_IN_BCOPY:
> > > > > -	  {
> > > > > -	    ao_ref dref;
> > > > > -	    tree size = gimple_call_arg (call, 2);
> > > > > -	    ao_ref_init_from_ptr_and_size (&dref,
> > > > > -					   gimple_call_arg (call, 1),
> > > > > -					   size);
> > > > > -	    return refs_may_alias_p_1 (&dref, ref, false);
> > > > > -	  }
> > > > > -	/* Allocating memory does not have any side-effects apart from
> > > > > -	   being the definition point for the pointer.  */
> > > > > -	case BUILT_IN_MALLOC:
> > > > > -	case BUILT_IN_ALIGNED_ALLOC:
> > > > > -	case BUILT_IN_CALLOC:
> > > > > -	case BUILT_IN_STRDUP:
> > > > > -	case BUILT_IN_STRNDUP:
> > > > > -	  /* Unix98 specifies that errno is set on allocation failure.  */
> > > > > -	  if (flag_errno_math
> > > > > -	      && targetm.ref_may_alias_errno (ref))
> > > > > -	    return true;
> > > > > -	  return false;
> > > > > -	case BUILT_IN_STACK_SAVE:
> > > > > -	CASE_BUILT_IN_ALLOCA:
> > > > > -	case BUILT_IN_ASSUME_ALIGNED:
> > > > > +      && gimple_call_builtin_p (call, BUILT_IN_NORMAL)
> > > > > +      && (ao_classify_builtin (callee, &info)))
> > > > > +    {
> > > > > +      if (info.flags & AO_FUNCTION_BARRIER)
> > > > > +	return true;
> > > > > +      if ((info.flags & AO_FUNCTION_ERRNO)
> > > > > +	  && flag_errno_math
> > > > > +	  && targetm.ref_may_alias_errno (ref))
> > > > > +	return true;
> > > > > +      if (info.num_param_writes >= 0)
> > > > > +	{
> > > > > +	  for (int i = 0; i < info.num_param_writes; i++)
> > > > > +	    {
> > > > > +	      ao_ref dref;
> > > > > +	      tree size = NULL_TREE;
> > > > > +
> > > > > +	      gcc_checking_assert (info.writes[i].size_param
> > > > > +				   != info.writes[i].param);
> > > > > +	      if (info.writes[i].size_param != -1)
> > > > > +		size = gimple_call_arg (call, info.writes[i].size_param);
> > > > > +	      else if (info.writes[i].size)
> > > > > +		size = build_int_cst (size_type_node, info.writes[i].size);
> > > > > +	      ao_ref_init_from_ptr_and_size (&dref,
> > > > > +					     gimple_call_arg
> > > > > +						 (call,
> > > > > +						  info.writes[i].param),
> > > > > +					     size);
> > > > > +	      if (refs_may_alias_p_1 (&dref, ref, tbaa_p))
> > > > > +		return true;
> > > > > +	    }
> > > > >  	  return false;
> > > > > -	/* But posix_memalign stores a pointer into the memory pointed to
> > > > > -	   by its first argument.  */
> > > > > -	case BUILT_IN_POSIX_MEMALIGN:
> > > > > -	  {
> > > > > -	    tree ptrptr = gimple_call_arg (call, 0);
> > > > > -	    ao_ref dref;
> > > > > -	    ao_ref_init_from_ptr_and_size (&dref, ptrptr,
> > > > > -					   TYPE_SIZE_UNIT (ptr_type_node));
> > > > > -	    return (refs_may_alias_p_1 (&dref, ref, false)
> > > > > -		    || (flag_errno_math
> > > > > -			&& targetm.ref_may_alias_errno (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.  */
> > > > > -	case BUILT_IN_FREE:
> > > > > -	case BUILT_IN_VA_END:
> > > > > -	  {
> > > > > -	    tree ptr = gimple_call_arg (call, 0);
> > > > > -	    return ptr_deref_may_alias_ref_p_1 (ptr, ref);
> > > > > -	  }
> > > > > -	/* Realloc serves both as allocation point and deallocation point.  */
> > > > > -	case BUILT_IN_REALLOC:
> > > > > -	  {
> > > > > -	    tree ptr = gimple_call_arg (call, 0);
> > > > > -	    /* Unix98 specifies that errno is set on allocation failure.  */
> > > > > -	    return ((flag_errno_math
> > > > > -		     && targetm.ref_may_alias_errno (ref))
> > > > > -		    || ptr_deref_may_alias_ref_p_1 (ptr, ref));
> > > > > -	  }
> > > > > -	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:
> > > > > -	  {
> > > > > -	    tree out = gimple_call_arg (call, 1);
> > > > > -	    if (ptr_deref_may_alias_ref_p_1 (out, ref))
> > > > > -	      return true;
> > > > > -	    if (flag_errno_math)
> > > > > -	      break;
> > > > > -	    return false;
> > > > > -	  }
> > > > > -	case BUILT_IN_FREXP:
> > > > > -	case BUILT_IN_FREXPF:
> > > > > -	case BUILT_IN_FREXPL:
> > > > > -	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_1 (out, ref);
> > > > > -	  }
> > > > > -	case BUILT_IN_REMQUO:
> > > > > -	case BUILT_IN_REMQUOF:
> > > > > -	case BUILT_IN_REMQUOL:
> > > > > -	  {
> > > > > -	    tree out = gimple_call_arg (call, 2);
> > > > > -	    if (ptr_deref_may_alias_ref_p_1 (out, ref))
> > > > > -	      return true;
> > > > > -	    if (flag_errno_math)
> > > > > -	      break;
> > > > > -	    return false;
> > > > > -	  }
> > > > > -	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);
> > > > > -	    return (ptr_deref_may_alias_ref_p_1 (sin, ref)
> > > > > -		    || ptr_deref_may_alias_ref_p_1 (cos, ref));
> > > > > -	  }
> > > > > -	/* __sync_* builtins and some OpenMP builtins act as threading
> > > > > -	   barriers.  */
> > > > > -#undef DEF_SYNC_BUILTIN
> > > > > -#define DEF_SYNC_BUILTIN(ENUM, NAME, TYPE, ATTRS) case ENUM:
> > > > > -#include "sync-builtins.def"
> > > > > -#undef DEF_SYNC_BUILTIN
> > > > > -	case BUILT_IN_GOMP_ATOMIC_START:
> > > > > -	case BUILT_IN_GOMP_ATOMIC_END:
> > > > > -	case BUILT_IN_GOMP_BARRIER:
> > > > > -	case BUILT_IN_GOMP_BARRIER_CANCEL:
> > > > > -	case BUILT_IN_GOMP_TASKWAIT:
> > > > > -	case BUILT_IN_GOMP_TASKGROUP_END:
> > > > > -	case BUILT_IN_GOMP_CRITICAL_START:
> > > > > -	case BUILT_IN_GOMP_CRITICAL_END:
> > > > > -	case BUILT_IN_GOMP_CRITICAL_NAME_START:
> > > > > -	case BUILT_IN_GOMP_CRITICAL_NAME_END:
> > > > > -	case BUILT_IN_GOMP_LOOP_END:
> > > > > -	case BUILT_IN_GOMP_LOOP_END_CANCEL:
> > > > > -	case BUILT_IN_GOMP_ORDERED_START:
> > > > > -	case BUILT_IN_GOMP_ORDERED_END:
> > > > > -	case BUILT_IN_GOMP_SECTIONS_END:
> > > > > -	case BUILT_IN_GOMP_SECTIONS_END_CANCEL:
> > > > > -	case BUILT_IN_GOMP_SINGLE_COPY_START:
> > > > > -	case BUILT_IN_GOMP_SINGLE_COPY_END:
> > > > > -	  return true;
> > > > > -	default:
> > > > > -	  /* Fallthru to general call handling.  */;
> > > > > -      }
> > > > > +	}
> > > > > +    }
> > > > >  
> > > > >    /* Check if base is a global static variable that is not written
> > > > >       by the function.  */
> > > > > 
> > > > 
> > > > -- 
> > > > Richard Biener <rguenther@suse.de>
> > > > SUSE Software Solutions Germany GmbH, Maxfeldstrasse 5, 90409 Nuernberg,
> > > > Germany; GF: Felix Imend
> > > 
> > > 
> > 
> > -- 
> > Richard Biener <rguenther@suse.de>
> > SUSE Software Solutions Germany GmbH, Maxfeldstrasse 5, 90409 Nuernberg,
> > Germany; GF: Felix Imend
> 
>
Jan Hubicka Sept. 28, 2020, 10:38 a.m. UTC | #6
> On Mon, 28 Sep 2020, Jan Hubicka wrote:
> 
> > > 
> > > Hmm, no - it expects the gimple_call_use/clobber_set to include
> > > actions of the called function itself (const functions none here)
> > > but for passed-by-value the loads may be in the call itself
> > > which is where it uses gimple_call_arg_flags to skip unused ones.
> > > 
> > > But note that PTA uses gimple_call_arg_flags to compute
> > > the gimple_call_use/clobber_set (but only in IPA mode) and the individual 
> > > BUILT_IN_* handlings in tree-ssa-alias.c do what PTA would do
> > > here, just directly as alias queries.  Originally I tried adding
> > > "fn spec"s to BUILT_IN_* decls but that got out-of-hands ...
> > 
> > Yep, I was also looking into that, it looks ugly and moreover the
> > attributes that depend on flag_math_errno and friends does not really
> > work for function speicfic attributes, so it is bug we handle them this
> > way.
> > 
> > Packing this into descriptor string in fnspec rather than descriptor
> > sturcture returned on side works for me (and we could add them to thinws
> > like C++ toplevel new/delete operator)
> > > 
> > > For example
> > > 
> > >         /* All the following functions read memory pointed to by
> > >            their second argument.  strcat/strncat additionally
> > >            reads memory pointed to by the first argument.  */
> > >         case BUILT_IN_STRCAT:
> > >         case BUILT_IN_STRNCAT:
> > >           {
> > >             ao_ref dref;
> > >             ao_ref_init_from_ptr_and_size (&dref,
> > >                                            gimple_call_arg (call, 0),
> > >                                            NULL_TREE);
> > >             if (refs_may_alias_p_1 (&dref, ref, false))
> > >               return true;
> > >           }
> > > 
> > > would be covered by "1WR" (W also implies read).  So the question
> > > would be whether at least parts of your patch could be implemented
> > > by making gimple_call_fnspec () return pre-determined fn-specs
> > > for BUILT_IN_* (like we do with internal_fn_fnspec).
> > 
> > One important change would be that we still need to figure out if the
> > function has other side effects.  Currently ref_maybe_used_by_call_p_1
> > first tries to prove that ref is local and can not be used by the
> > function unless it is passed as parameter value and then it looks into
> > fnspec if the parameter is used.
> > 
> > For builtins it constructs tests based on the builtin type and bypasses
> > the rest since it knows that all side effects are understood.
> > 
> > As far as I can tell, fn spec isused only by fortran for library calls,
> > so perhaps it would not be too hard to turn fn spec semantics from "some
> > properties of parameter handling are known" to "all memory accesses are
> > known" or have additional way to indicate this.
> 
> Yeah, currently "fn spec" only says we know everything with respect
> to a specific parameter but not the whole function.  We'd naturally
> say the function is 'const' besides what specified by "fn spec" but
> of course we cannot really use 'const' for this how.
> 
> > I guess space in return value predictor could be reserved for this, or
> > we could have extra flags section at the begining.
> 
> Yeah, I think we want pure/const/unknown, so p,c,u with
> upper case denoting 'errno' is clobbered (eh...).

Sounds good to me
> 
> > > 
> > > >  We would need
> > > > to invent how to add info that non pure/const function only access the
> > > > argument according to fn spec, add way to represent sizes of accesses
> > > > and how to handle errno.
> > > 
> > > True - fn-spec lacks an ability to specify access size - fortunately
> > > it's internal and we could change it ;)  Whether or not sth can clobber
> > > errno is sth we eventually need to move to the stmt level anyway
> > > (-f[no-]math-errno crossing inline boundary) - bit sad to waste a
> > > bit in a gimple call for this though.  OTOH we waste a ton of space
> > > in the call_used/call_clobbered members due to bad packing
> > > (unsigned int bitfield followed by a pointer to a bitmap).  Eventually
> > > we could offload this kind of info from the main stmt.  We could
> > > also allocate a fake UID to represent errno (but then the rest of
> > > the bits in call_used/call_clobbered have to be precise) - but note
> > > call_used/call_clobbered does not transfer during inlining.
> > > 
> > > So for the access size issue we could blow up fnspec by factor of two,
> > > reserving two chars per argument/return value and do
> > > 
> > >  1.W3R.
> > 
> > We also have known bytesizes like return values of sincos
> > (where the size really matters on the size of type that is known only at
> > runtime).
> > That can be 3 digits if represented decimally (or two digits hex, but
> > it may become too small in future with vector types)
> 
> Hmm, we can use Wt for 'formal argument type', so sincos 'double *'
> would mean 'double'?  Not sure if that's enough for all cases.

We currently handle only sincos and memalign, but there are also things
like tm load/store builtins that could do the same.
> 
> > One option would be make the unit to be the size of pointer pointed to,
> > tat would turn it to be 1 in all cases we handle. Then we could blow up
> > by 3 and have something like P1 meaning "size is described by parameter
> > numer 1" and "10" meaning 10 elements are written by the function.
> 
> So for the case we have int * and int n parameter and the size is
> n * sizeof (int) you mean?  Do we have this complicated cases for
> builtins?  We could also add some escape mechanism (double-ick),
In the two examples handled this is always 1.  But I wonder if vector
builtins would fit naturally to that.
> like Wl 'literal' meaning the actual value is appended to the
> fn spec.  Thus int foo (int *p, unsigned) writing 54 items to *p
> would be ..Wl..54 ... (and L for 4-char literal).  For scaling
> by typeof (*p) we could use a-z instead of 1-9 to refer to the
> parameter in question.  So yeah, it gets a bit fugly if overloaded
> too heavily.

Since I think fn spec are yours, it would be great if you could write me
a short spec on the semantics of the string and I could imlement it.

Honza
> 
> > > for strncat plus add gimple_call_arg_size to access it.  The 2nd
> > > slot in return value could host the errno thing (eh).
> > > 
> > >  .e
> > > 
> > > for sqrt for example.
> > > 
> > > Just to repeat again - the info looks too similar to warrant an
> > > extra mechanism to record it.
> > 
> > No problem, just if we figure way to do so :)
> 
> Yes indeed.
> 
> Richard.
> 
> > > 
> > > Richard.
> > > 
> > > > Honza
> > > > > 
> > > > > > gcc/ChangeLog:
> > > > > > 
> > > > > > 2020-09-28  Jan Hubicka  <hubicka@ucw.cz>
> > > > > > 
> > > > > > 	* tree-ssa-alias.c (ao_classify_builtin): New function commonizing
> > > > > > 	logic from ...
> > > > > > 	(ref_maybe_used_by_call_p_1): ... here.
> > > > > > 	(call_may_clobber_ref_p_1): ... and here.
> > > > > > 	* tree-ssa-alias.h (enum ao_function_flags): New enum.
> > > > > > 	(struct ao_function_info): New structure.
> > > > > > 	(ao_classify_builtin): Declare.
> > > > > > 
> > > > > > diff --git a/gcc/tree-ssa-alias.h b/gcc/tree-ssa-alias.h
> > > > > > index 1dd02c0ea62..eecb8da6dd7 100644
> > > > > > --- a/gcc/tree-ssa-alias.h
> > > > > > +++ b/gcc/tree-ssa-alias.h
> > > > > > @@ -108,6 +108,33 @@ ao_ref::max_size_known_p () const
> > > > > >    return known_size_p (max_size);
> > > > > >  }
> > > > > >  
> > > > > > +/* Flags used in ao_function_info.  */
> > > > > > +
> > > > > > +enum ao_function_flags
> > > > > > +{
> > > > > > +  AO_FUNCTION_BARRIER = 1,
> > > > > > +  AO_FUNCTION_ERRNO = 2,
> > > > > > +};
> > > > > > +
> > > > > > +/* Describe side effects relevant for alias analysis of function call to
> > > > > > +   DECL.  */
> > > > > > +
> > > > > > +struct ao_function_info
> > > > > > +{
> > > > > > +  int num_param_reads;  /* Number of parameters function reads from,
> > > > > > +			   -1 if reads are unknown.  */
> > > > > > +  struct ao_access_info
> > > > > > +    {
> > > > > > +      char param; 	/* Index of parameter read/written from.  */
> > > > > > +      char size_param;	/* Index of parameter specifying size of the access,
> > > > > > +			   -1 if unknown.  */
> > > > > > +      char size;	/* Size of access if known, 0 if unknown.  */
> > > > > > +    } reads[2];
> > > > > > +  int num_param_writes;
> > > > > > +  struct ao_access_info writes[2];
> > > > > > +  enum ao_function_flags flags;
> > > > > > +};
> > > > > > +
> > > > > >  /* In tree-ssa-alias.c  */
> > > > > >  extern void ao_ref_init (ao_ref *, tree);
> > > > > >  extern void ao_ref_init_from_ptr_and_size (ao_ref *, tree, tree);
> > > > > > @@ -158,6 +185,7 @@ extern void debug (pt_solution *ptr);
> > > > > >  extern void dump_points_to_info_for (FILE *, tree);
> > > > > >  extern void debug_points_to_info_for (tree);
> > > > > >  extern void dump_alias_stats (FILE *);
> > > > > > +extern bool ao_classify_builtin (tree callee, ao_function_info *info);
> > > > > >  
> > > > > >  
> > > > > >  /* In tree-ssa-structalias.c  */
> > > > > > diff --git a/gcc/tree-ssa-alias.c b/gcc/tree-ssa-alias.c
> > > > > > index fe390d4ffbe..c182e7bb39c 100644
> > > > > > --- a/gcc/tree-ssa-alias.c
> > > > > > +++ b/gcc/tree-ssa-alias.c
> > > > > > @@ -2503,6 +2503,507 @@ modref_may_conflict (const gimple *stmt,
> > > > > >    return false;
> > > > > >  }
> > > > > >  
> > > > > > +/* If CALLEE has known side effects, fill in INFO and return true.
> > > > > > +   See tree-ssa-structalias.c:find_func_aliases
> > > > > > +   for the list of builtins we might need to handle here.  */
> > > > > > +
> > > > > > +bool
> > > > > > +ao_classify_builtin (tree callee, ao_function_info *info)
> > > > > > +{
> > > > > > +  built_in_function code = DECL_FUNCTION_CODE (callee);
> > > > > > +
> > > > > > +  switch (code)
> > > > > > +    {
> > > > > > +      /* All the following functions read memory pointed to by
> > > > > > +	 their second argument and write memory pointed to by first
> > > > > > +	 argument.
> > > > > > +	 strcat/strncat additionally reads memory pointed to by the first
> > > > > > +	 argument.  */
> > > > > > +      case BUILT_IN_STRCAT:
> > > > > > +	{
> > > > > > +	  const static struct ao_function_info ret_info
> > > > > > +	       = {
> > > > > > +		    2,				/* num_param_reads.  */
> > > > > > +
> > > > > > +		    /* Reads and write descriptors are triples containing:
> > > > > > +		       - index of parameter read
> > > > > > +		       - index of parameter specifying access size
> > > > > > +			 (-1 if unknown)
> > > > > > +		       - access size in bytes (0 if unkown).  */
> > > > > > +
> > > > > > +		    {{0, -1, 0}, {1, -1, 0}},	/* Param read.  */
> > > > > > +		    1,				/* num_param_writes.  */
> > > > > > +		    {{0, -1, 0}},		/* Param written.  */
> > > > > > +		    (ao_function_flags)0,	/* flags.  */
> > > > > > +		 };
> > > > > > +	  *info = ret_info;
> > > > > > +	  return true;
> > > > > > +	}
> > > > > > +      case BUILT_IN_STRNCAT:
> > > > > > +	{
> > > > > > +	  const static struct ao_function_info ret_info
> > > > > > +	       = {
> > > > > > +		    2,				/* num_param_reads.  */
> > > > > > +		    {{0, -1, 0}, {1, 2, 0}},	/* Param read.  */
> > > > > > +		    1,				/* num_param_writes.  */
> > > > > > +		    {{0, -1, 0}},		/* Param written.  */
> > > > > > +		    (ao_function_flags)0,	/* flags.  */
> > > > > > +		 };
> > > > > > +	  *info = ret_info;
> > > > > > +	  return true;
> > > > > > +	}
> > > > > > +      case BUILT_IN_STRCPY:
> > > > > > +      case BUILT_IN_STPCPY:
> > > > > > +	{
> > > > > > +	  const static struct ao_function_info ret_info
> > > > > > +	       = {
> > > > > > +		    1,				/* num_param_reads.  */
> > > > > > +		    {{1, -1, 0}},		/* Param read.  */
> > > > > > +		    1,				/* num_param_writes.  */
> > > > > > +		    {{0, -1, 0}},		/* Param written.  */
> > > > > > +		    (ao_function_flags)0,	/* flags.  */
> > > > > > +		 };
> > > > > > +	  *info = ret_info;
> > > > > > +	  return true;
> > > > > > +	}
> > > > > > +      case BUILT_IN_STRNCPY:
> > > > > > +      case BUILT_IN_MEMCPY:
> > > > > > +      case BUILT_IN_MEMMOVE:
> > > > > > +      case BUILT_IN_MEMPCPY:
> > > > > > +      case BUILT_IN_STPNCPY:
> > > > > > +      case BUILT_IN_TM_MEMCPY:
> > > > > > +      case BUILT_IN_TM_MEMMOVE:
> > > > > > +	{
> > > > > > +	  const static struct ao_function_info ret_info
> > > > > > +	       = {
> > > > > > +		    1,				/* num_param_reads.  */
> > > > > > +		    {{1, 2, 0}},		/* Param read.  */
> > > > > > +		    1,				/* num_param_writes.  */
> > > > > > +		    {{0, 2, 0}},		/* Param written.  */
> > > > > > +		    (ao_function_flags)0,	/* flags.  */
> > > > > > +		 };
> > > > > > +	  *info = ret_info;
> > > > > > +	  return true;
> > > > > > +	}
> > > > > > +      case BUILT_IN_STRCAT_CHK:
> > > > > > +	{
> > > > > > +	  const static struct ao_function_info ret_info
> > > > > > +	       = {
> > > > > > +		    2,				/* num_param_reads.  */
> > > > > > +		    {{0, -1, 0}, {1, -1, 0}},	/* Param read.  */
> > > > > > +		    1,				/* num_param_writes.  */
> > > > > > +		    {{0, -1, 0}},		/* Param written.  */
> > > > > > +		    (ao_function_flags)0,	/* flags.  */
> > > > > > +		 };
> > > > > > +	  *info = ret_info;
> > > > > > +	  return true;
> > > > > > +	}
> > > > > > +      case BUILT_IN_STRNCAT_CHK:
> > > > > > +	{
> > > > > > +	  const static struct ao_function_info ret_info
> > > > > > +	       = {
> > > > > > +		    2,				/* num_param_reads.  */
> > > > > > +		    {{0, -1, 0}, {1, 2, 0}},	/* Param read.  */
> > > > > > +		    1,				/* num_param_writes.  */
> > > > > > +		    {{0, -1, 0}},		/* Param written.  */
> > > > > > +		    (ao_function_flags)0,	/* flags.  */
> > > > > > +		 };
> > > > > > +	  *info = ret_info;
> > > > > > +	  return true;
> > > > > > +	}
> > > > > > +      case BUILT_IN_STRCPY_CHK:
> > > > > > +      case BUILT_IN_STPCPY_CHK:
> > > > > > +	{
> > > > > > +	  const static struct ao_function_info ret_info
> > > > > > +	       = {
> > > > > > +		    1,				/* num_param_reads.  */
> > > > > > +		    {{1, -1, 0}},		/* Param read.  */
> > > > > > +		    1,				/* num_param_writes.  */
> > > > > > +		    {{0, -1, 0}},		/* Param written.  */
> > > > > > +		    (ao_function_flags)0,	/* flags.  */
> > > > > > +		 };
> > > > > > +	  *info = ret_info;
> > > > > > +	  return true;
> > > > > > +	}
> > > > > > +      case BUILT_IN_STRNCPY_CHK:
> > > > > > +      case BUILT_IN_MEMCPY_CHK:
> > > > > > +      case BUILT_IN_MEMMOVE_CHK:
> > > > > > +      case BUILT_IN_MEMPCPY_CHK:
> > > > > > +      case BUILT_IN_STPNCPY_CHK:
> > > > > > +	{
> > > > > > +	  const static struct ao_function_info ret_info
> > > > > > +	       = {
> > > > > > +		    1,				/* num_param_reads.  */
> > > > > > +		    {{1, 2, 0}},		/* Param read.  */
> > > > > > +		    1,				/* num_param_writes.  */
> > > > > > +		    {{0, 2, 0}},		/* Param written.  */
> > > > > > +		    (ao_function_flags)0,	/* flags.  */
> > > > > > +		 };
> > > > > > +	  *info = ret_info;
> > > > > > +	  return true;
> > > > > > +	}
> > > > > > +      case BUILT_IN_BCOPY:
> > > > > > +	{
> > > > > > +	  const static struct ao_function_info ret_info
> > > > > > +	       = {
> > > > > > +		    1,				/* num_param_reads.  */
> > > > > > +		    {{0, 2, 0}},		/* Param read.  */
> > > > > > +		    1,				/* num_param_writes.  */
> > > > > > +		    {{1, 2, 0}},		/* Param written.  */
> > > > > > +		    (ao_function_flags)0,	/* flags.  */
> > > > > > +		 };
> > > > > > +	  *info = ret_info;
> > > > > > +	  return true;
> > > > > > +	}
> > > > > > +
> > > > > > +      /* The following functions read memory pointed to by their
> > > > > > +	 first argument.  */
> > > > > > +      CASE_BUILT_IN_TM_LOAD (1):
> > > > > > +      CASE_BUILT_IN_TM_LOAD (2):
> > > > > > +      CASE_BUILT_IN_TM_LOAD (4):
> > > > > > +      CASE_BUILT_IN_TM_LOAD (8):
> > > > > > +      CASE_BUILT_IN_TM_LOAD (FLOAT):
> > > > > > +      CASE_BUILT_IN_TM_LOAD (DOUBLE):
> > > > > > +      CASE_BUILT_IN_TM_LOAD (LDOUBLE):
> > > > > > +      CASE_BUILT_IN_TM_LOAD (M64):
> > > > > > +      CASE_BUILT_IN_TM_LOAD (M128):
> > > > > > +      CASE_BUILT_IN_TM_LOAD (M256):
> > > > > > +      case BUILT_IN_TM_LOG:
> > > > > > +      case BUILT_IN_TM_LOG_1:
> > > > > > +      case BUILT_IN_TM_LOG_2:
> > > > > > +      case BUILT_IN_TM_LOG_4:
> > > > > > +      case BUILT_IN_TM_LOG_8:
> > > > > > +      case BUILT_IN_TM_LOG_FLOAT:
> > > > > > +      case BUILT_IN_TM_LOG_DOUBLE:
> > > > > > +      case BUILT_IN_TM_LOG_LDOUBLE:
> > > > > > +      case BUILT_IN_TM_LOG_M64:
> > > > > > +      case BUILT_IN_TM_LOG_M128:
> > > > > > +      case BUILT_IN_TM_LOG_M256:
> > > > > > +
> > > > > > +      case BUILT_IN_INDEX:
> > > > > > +      case BUILT_IN_STRCHR:
> > > > > > +      case BUILT_IN_STRRCHR:
> > > > > > +	{
> > > > > > +	  const static struct ao_function_info ret_info
> > > > > > +	       = {
> > > > > > +		    1,				/* num_param_reads.  */
> > > > > > +		    /* TODO: For TM builtins size is known.  */
> > > > > > +		    {{0, -1, 0}},		/* Param read.  */
> > > > > > +		    0,				/* num_param_writes.  */
> > > > > > +		    {},				/* Param written.  */
> > > > > > +		    (ao_function_flags)0,	/* flags.  */
> > > > > > +		 };
> > > > > > +	  *info = ret_info;
> > > > > > +	  return true;
> > > > > > +	}
> > > > > > +
> > > > > > +      /* These read memory pointed to by the first argument.
> > > > > > +	 Allocating memory does not have any side-effects apart from
> > > > > > +	 being the definition point for the pointer.
> > > > > > +	 Unix98 specifies that errno is set on allocation failure.  */
> > > > > > +      case BUILT_IN_STRDUP:
> > > > > > +	{
> > > > > > +	  const static struct ao_function_info ret_info
> > > > > > +	       = {
> > > > > > +		    1,				/* num_param_reads.  */
> > > > > > +		    {{0, -1, 0}},		/* Param read.  */
> > > > > > +		    0,				/* num_param_writes.  */
> > > > > > +		    {},				/* Param written.  */
> > > > > > +		    AO_FUNCTION_ERRNO,		/* flags.  */
> > > > > > +		 };
> > > > > > +	  *info = ret_info;
> > > > > > +	  return true;
> > > > > > +	}
> > > > > > +      case BUILT_IN_STRNDUP:
> > > > > > +	{
> > > > > > +	  const static struct ao_function_info ret_info
> > > > > > +	       = {
> > > > > > +		    1,				/* num_param_reads.  */
> > > > > > +		    {{0, 1, 0}},		/* Param read.  */
> > > > > > +		    0,				/* num_param_writes.  */
> > > > > > +		    {},				/* Param written.  */
> > > > > > +		    AO_FUNCTION_ERRNO,		/* flags.  */
> > > > > > +		 };
> > > > > > +	  *info = ret_info;
> > > > > > +	  return true;
> > > > > > +	}
> > > > > > +      /* Allocating memory does not have any side-effects apart from
> > > > > > +	 being the definition point for the pointer.  */
> > > > > > +      case BUILT_IN_MALLOC:
> > > > > > +      case BUILT_IN_ALIGNED_ALLOC:
> > > > > > +      case BUILT_IN_CALLOC:
> > > > > > +	{
> > > > > > +	  const static struct ao_function_info ret_info
> > > > > > +	       = {
> > > > > > +		    0,				/* num_param_reads.  */
> > > > > > +		    {},				/* Param read.  */
> > > > > > +		    0,				/* num_param_writes.  */
> > > > > > +		    {},				/* Param written.  */
> > > > > > +		    AO_FUNCTION_ERRNO,		/* flags.  */
> > > > > > +		 };
> > > > > > +	  *info = ret_info;
> > > > > > +	  return true;
> > > > > > +	}
> > > > > > +      /* These read memory pointed to by the first argument with size
> > > > > > +	 in the third argument.  */
> > > > > > +      case BUILT_IN_MEMCHR:
> > > > > > +	{
> > > > > > +	  const static struct ao_function_info ret_info
> > > > > > +	       = {
> > > > > > +		    1,				/* num_param_reads.  */
> > > > > > +		    {{0, 2, 0}},		/* Param read.  */
> > > > > > +		    0,				/* num_param_writes.  */
> > > > > > +		    {},				/* Param written.  */
> > > > > > +		    (ao_function_flags)0,	/* flags.  */
> > > > > > +		 };
> > > > > > +	  *info = ret_info;
> > > > > > +	  return true;
> > > > > > +	}
> > > > > > +      /* These read memory pointed to by the first and second arguments.  */
> > > > > > +      case BUILT_IN_STRSTR:
> > > > > > +      case BUILT_IN_STRPBRK:
> > > > > > +	{
> > > > > > +	  static struct ao_function_info ret_info
> > > > > > +	       = {
> > > > > > +		    2,				/* num_param_reads.  */
> > > > > > +		    {{0, -1, 0}, {1, -1, 0}},	/* Param read.  */
> > > > > > +		    0,				/* num_param_writes.  */
> > > > > > +		    {},				/* Param written.  */
> > > > > > +		    (ao_function_flags)0,	/* flags.  */
> > > > > > +		 };
> > > > > > +	  *info = ret_info;
> > > > > > +	  return true;
> > > > > > +	}
> > > > > > +      /* Freeing memory kills the pointed-to memory.  More importantly
> > > > > > +	 the call has to serve as a barrier for moving loads and stores
> > > > > > +	 across it.  */
> > > > > > +      case BUILT_IN_FREE:
> > > > > > +      case BUILT_IN_VA_END:
> > > > > > +	{
> > > > > > +	  const static struct ao_function_info ret_info
> > > > > > +	       = {
> > > > > > +		    0,				/* num_param_reads.  */
> > > > > > +		    {},				/* Param read.  */
> > > > > > +		    1,				/* num_param_writes.  */
> > > > > > +		    {{0, -1, 0}},		/* Param written.  */
> > > > > > +		    (ao_function_flags)0,	/* flags.  */
> > > > > > +		 };
> > > > > > +	  *info = ret_info;
> > > > > > +	  return true;
> > > > > > +	}
> > > > > > +      /* Realloc serves both as allocation point and deallocation point.  */
> > > > > > +      case BUILT_IN_REALLOC:
> > > > > > +	{
> > > > > > +	  const static struct ao_function_info ret_info
> > > > > > +	       = {
> > > > > > +		    1,				/* num_param_reads.  */
> > > > > > +		    {{0, 1, 0}},		/* Param read.  */
> > > > > > +		    0,				/* num_param_writes.  */
> > > > > > +		    {{0, -1, 0}},		/* Param written.  */
> > > > > > +		    AO_FUNCTION_ERRNO,		/* flags.  */
> > > > > > +		 };
> > > > > > +	  *info = ret_info;
> > > > > > +	  return true;
> > > > > > +	}
> > > > > > +      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:
> > > > > > +	{
> > > > > > +	  const static struct ao_function_info ret_info
> > > > > > +	       = {
> > > > > > +		    0,				/* num_param_reads.  */
> > > > > > +		    {},				/* Param read.  */
> > > > > > +		    1,				/* num_param_writes.  */
> > > > > > +		    {{1, -1, 0}},		/* Param written.  */
> > > > > > +		    AO_FUNCTION_ERRNO,		/* flags.  */
> > > > > > +		 };
> > > > > > +	  *info = ret_info;
> > > > > > +	  return true;
> > > > > > +	}
> > > > > > +      case BUILT_IN_FREXP:
> > > > > > +      case BUILT_IN_FREXPF:
> > > > > > +      case BUILT_IN_FREXPL:
> > > > > > +      case BUILT_IN_MODF:
> > > > > > +      case BUILT_IN_MODFF:
> > > > > > +      case BUILT_IN_MODFL:
> > > > > > +	{
> > > > > > +	  const static struct ao_function_info ret_info
> > > > > > +	       = {
> > > > > > +		    0,				/* num_param_reads.  */
> > > > > > +		    {},				/* Param read.  */
> > > > > > +		    1,				/* num_param_writes.  */
> > > > > > +		    {{1, -1, 0}},		/* Param written.  */
> > > > > > +		    (ao_function_flags)0,	/* flags.  */
> > > > > > +		 };
> > > > > > +	  *info = ret_info;
> > > > > > +	  return true;
> > > > > > +	}
> > > > > > +      case BUILT_IN_REMQUO:
> > > > > > +      case BUILT_IN_REMQUOF:
> > > > > > +      case BUILT_IN_REMQUOL:
> > > > > > +	{
> > > > > > +	  const static struct ao_function_info ret_info
> > > > > > +	       = {
> > > > > > +		    0,				/* num_param_reads.  */
> > > > > > +		    {},				/* Param read.  */
> > > > > > +		    1,				/* num_param_writes.  */
> > > > > > +		    {{2, -1, 0}},		/* Param written.  */
> > > > > > +		    (ao_function_flags)0,	/* flags.  */
> > > > > > +		 };
> > > > > > +	  *info = ret_info;
> > > > > > +	  return true;
> > > > > > +	}
> > > > > > +      case BUILT_IN_SINCOS:
> > > > > > +      case BUILT_IN_SINCOSF:
> > > > > > +      case BUILT_IN_SINCOSL:
> > > > > > +	{
> > > > > > +	  static struct ao_function_info ret_info
> > > > > > +	       = {
> > > > > > +		    0,				/* num_param_reads.  */
> > > > > > +		    {},				/* Param read.  */
> > > > > > +		    1,				/* num_param_writes.  */
> > > > > > +		    {{1, -1, 0}, {2, -1, 0}},	/* Param written.  */
> > > > > > +		    (ao_function_flags)0,	/* flags.  */
> > > > > > +		 };
> > > > > > +	  tree type = float_ptr_type_node;
> > > > > > +	  if (code == BUILT_IN_SINCOS)
> > > > > > +	    type = double_ptr_type_node;
> > > > > > +	  else
> > > > > > +	    type = long_double_ptr_type_node;
> > > > > > +	  ret_info.writes[0].size = ret_info.writes[1].size
> > > > > > +		 = tree_to_uhwi (TYPE_SIZE_UNIT (type));
> > > > > > +	  *info = ret_info;
> > > > > > +	  return true;
> > > > > > +	}
> > > > > > +      case BUILT_IN_MEMSET:
> > > > > > +      case BUILT_IN_MEMSET_CHK:
> > > > > > +      case BUILT_IN_TM_MEMSET:
> > > > > > +	{
> > > > > > +	  const static struct ao_function_info ret_info
> > > > > > +	       = {
> > > > > > +		    0,				/* num_param_reads.  */
> > > > > > +		    {},				/* Param read.  */
> > > > > > +		    1,				/* num_param_writes.  */
> > > > > > +		    {0, 2, 0},			/* Param written.  */
> > > > > > +		    (ao_function_flags)0,	/* flags.  */
> > > > > > +		 };
> > > > > > +	  *info = ret_info;
> > > > > > +	  return true;
> > > > > > +	}
> > > > > > +      CASE_BUILT_IN_TM_STORE (1):
> > > > > > +      CASE_BUILT_IN_TM_STORE (2):
> > > > > > +      CASE_BUILT_IN_TM_STORE (4):
> > > > > > +      CASE_BUILT_IN_TM_STORE (8):
> > > > > > +      CASE_BUILT_IN_TM_STORE (FLOAT):
> > > > > > +      CASE_BUILT_IN_TM_STORE (DOUBLE):
> > > > > > +      CASE_BUILT_IN_TM_STORE (LDOUBLE):
> > > > > > +      CASE_BUILT_IN_TM_STORE (M64):
> > > > > > +      CASE_BUILT_IN_TM_STORE (M128):
> > > > > > +      CASE_BUILT_IN_TM_STORE (M256):
> > > > > > +	{
> > > > > > +	  const static struct ao_function_info ret_info
> > > > > > +	       = {
> > > > > > +		    0,				/* num_param_reads.  */
> > > > > > +		    {},				/* Param read.  */
> > > > > > +		    1,				/* num_param_writes.  */
> > > > > > +		    /* TODO: Size is known.  */
> > > > > > +		    {0, -1, 0},			/* Param written.  */
> > > > > > +		    (ao_function_flags)0,	/* flags.  */
> > > > > > +		 };
> > > > > > +	  *info = ret_info;
> > > > > > +	  return true;
> > > > > > +	}
> > > > > > +      case BUILT_IN_STACK_SAVE:
> > > > > > +      CASE_BUILT_IN_ALLOCA:
> > > > > > +      case BUILT_IN_ASSUME_ALIGNED:
> > > > > > +	{
> > > > > > +	  const static struct ao_function_info ret_info
> > > > > > +	       = {
> > > > > > +		    0,				/* num_param_reads.  */
> > > > > > +		    {},				/* Param read.  */
> > > > > > +		    0,				/* num_param_writes.  */
> > > > > > +		    {},				/* Param written.  */
> > > > > > +		    (ao_function_flags)0,	/* flags.  */
> > > > > > +		 };
> > > > > > +	  *info = ret_info;
> > > > > > +	  return true;
> > > > > > +	}
> > > > > > +      /* But posix_memalign stores a pointer into the memory pointed to
> > > > > > +	 by its first argument.  */
> > > > > > +      case BUILT_IN_POSIX_MEMALIGN:
> > > > > > +	{
> > > > > > +	  static struct ao_function_info ret_info
> > > > > > +	       = {
> > > > > > +		    0,				/* num_param_reads.  */
> > > > > > +		    {},				/* Param read.  */
> > > > > > +		    0,				/* num_param_writes.  */
> > > > > > +		    {{0, -1, 0}},		/* Param written.  */
> > > > > > +		    AO_FUNCTION_ERRNO,		/* flags.  */
> > > > > > +		 };
> > > > > > +	  ret_info.writes[0].size
> > > > > > +		 = tree_to_uhwi (TYPE_SIZE_UNIT (ptr_type_node));
> > > > > > +	  *info = ret_info;
> > > > > > +	  return true;
> > > > > > +	}
> > > > > > +      /* The following builtins do not read from memory.  */
> > > > > > +      case BUILT_IN_STACK_RESTORE:
> > > > > > +	{
> > > > > > +	  const static struct ao_function_info ret_info
> > > > > > +	       = {
> > > > > > +		    0,				/* num_param_reads.  */
> > > > > > +		    {},				/* Param read.  */
> > > > > > +		    0,				/* num_param_writes.  */
> > > > > > +		    {},				/* Param written.  */
> > > > > > +		    (ao_function_flags)0,	/* flags.  */
> > > > > > +		 };
> > > > > > +	  *info = ret_info;
> > > > > > +	  return true;
> > > > > > +	}
> > > > > > +      /* __sync_* builtins and some OpenMP builtins act as threading
> > > > > > +	 barriers.  */
> > > > > > +#undef DEF_SYNC_BUILTIN
> > > > > > +#define DEF_SYNC_BUILTIN(ENUM, NAME, TYPE, ATTRS) case ENUM:
> > > > > > +#include "sync-builtins.def"
> > > > > > +#undef DEF_SYNC_BUILTIN
> > > > > > +      case BUILT_IN_GOMP_ATOMIC_START:
> > > > > > +      case BUILT_IN_GOMP_ATOMIC_END:
> > > > > > +      case BUILT_IN_GOMP_BARRIER:
> > > > > > +      case BUILT_IN_GOMP_BARRIER_CANCEL:
> > > > > > +      case BUILT_IN_GOMP_TASKWAIT:
> > > > > > +      case BUILT_IN_GOMP_TASKGROUP_END:
> > > > > > +      case BUILT_IN_GOMP_CRITICAL_START:
> > > > > > +      case BUILT_IN_GOMP_CRITICAL_END:
> > > > > > +      case BUILT_IN_GOMP_CRITICAL_NAME_START:
> > > > > > +      case BUILT_IN_GOMP_CRITICAL_NAME_END:
> > > > > > +      case BUILT_IN_GOMP_LOOP_END:
> > > > > > +      case BUILT_IN_GOMP_LOOP_END_CANCEL:
> > > > > > +      case BUILT_IN_GOMP_ORDERED_START:
> > > > > > +      case BUILT_IN_GOMP_ORDERED_END:
> > > > > > +      case BUILT_IN_GOMP_SECTIONS_END:
> > > > > > +      case BUILT_IN_GOMP_SECTIONS_END_CANCEL:
> > > > > > +      case BUILT_IN_GOMP_SINGLE_COPY_START:
> > > > > > +      case BUILT_IN_GOMP_SINGLE_COPY_END:
> > > > > > +	{
> > > > > > +	  const static struct ao_function_info ret_info
> > > > > > +	       = {
> > > > > > +		    -1,				/* num_param_reads.  */
> > > > > > +		    {},				/* Param read.  */
> > > > > > +		    -1,				/* num_param_writes.  */
> > > > > > +		    {},				/* Param written.  */
> > > > > > +		    AO_FUNCTION_BARRIER,	/* flags.  */
> > > > > > +		 };
> > > > > > +	  *info = ret_info;
> > > > > > +	  return true;
> > > > > > +	}
> > > > > > +
> > > > > > +      default:
> > > > > > +	return false;
> > > > > > +    }
> > > > > > +}
> > > > > > +
> > > > > >  /* If the call CALL may use the memory reference REF return true,
> > > > > >     otherwise return false.  */
> > > > > >  
> > > > > > @@ -2574,219 +3075,37 @@ ref_maybe_used_by_call_p_1 (gcall *call, ao_ref *ref, bool tbaa_p)
> > > > > >    /* 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.  */
> > > > > > +  struct ao_function_info info;
> > > > > >    if (callee != NULL_TREE
> > > > > > -      && gimple_call_builtin_p (call, BUILT_IN_NORMAL))
> > > > > > -    switch (DECL_FUNCTION_CODE (callee))
> > > > > > -      {
> > > > > > -	/* All the following functions read memory pointed to by
> > > > > > -	   their second argument.  strcat/strncat additionally
> > > > > > -	   reads memory pointed to by the first argument.  */
> > > > > > -	case BUILT_IN_STRCAT:
> > > > > > -	case BUILT_IN_STRNCAT:
> > > > > > -	  {
> > > > > > -	    ao_ref dref;
> > > > > > -	    ao_ref_init_from_ptr_and_size (&dref,
> > > > > > -					   gimple_call_arg (call, 0),
> > > > > > -					   NULL_TREE);
> > > > > > -	    if (refs_may_alias_p_1 (&dref, ref, false))
> > > > > > -	      return true;
> > > > > > -	  }
> > > > > > -	  /* FALLTHRU */
> > > > > > -	case BUILT_IN_STRCPY:
> > > > > > -	case BUILT_IN_STRNCPY:
> > > > > > -	case BUILT_IN_MEMCPY:
> > > > > > -	case BUILT_IN_MEMMOVE:
> > > > > > -	case BUILT_IN_MEMPCPY:
> > > > > > -	case BUILT_IN_STPCPY:
> > > > > > -	case BUILT_IN_STPNCPY:
> > > > > > -	case BUILT_IN_TM_MEMCPY:
> > > > > > -	case BUILT_IN_TM_MEMMOVE:
> > > > > > -	  {
> > > > > > -	    ao_ref dref;
> > > > > > -	    tree size = NULL_TREE;
> > > > > > -	    if (gimple_call_num_args (call) == 3)
> > > > > > -	      size = gimple_call_arg (call, 2);
> > > > > > -	    ao_ref_init_from_ptr_and_size (&dref,
> > > > > > -					   gimple_call_arg (call, 1),
> > > > > > -					   size);
> > > > > > -	    return refs_may_alias_p_1 (&dref, ref, false);
> > > > > > -	  }
> > > > > > -	case BUILT_IN_STRCAT_CHK:
> > > > > > -	case BUILT_IN_STRNCAT_CHK:
> > > > > > -	  {
> > > > > > -	    ao_ref dref;
> > > > > > -	    ao_ref_init_from_ptr_and_size (&dref,
> > > > > > -					   gimple_call_arg (call, 0),
> > > > > > -					   NULL_TREE);
> > > > > > -	    if (refs_may_alias_p_1 (&dref, ref, false))
> > > > > > -	      return true;
> > > > > > -	  }
> > > > > > -	  /* FALLTHRU */
> > > > > > -	case BUILT_IN_STRCPY_CHK:
> > > > > > -	case BUILT_IN_STRNCPY_CHK:
> > > > > > -	case BUILT_IN_MEMCPY_CHK:
> > > > > > -	case BUILT_IN_MEMMOVE_CHK:
> > > > > > -	case BUILT_IN_MEMPCPY_CHK:
> > > > > > -	case BUILT_IN_STPCPY_CHK:
> > > > > > -	case BUILT_IN_STPNCPY_CHK:
> > > > > > -	  {
> > > > > > -	    ao_ref dref;
> > > > > > -	    tree size = NULL_TREE;
> > > > > > -	    if (gimple_call_num_args (call) == 4)
> > > > > > -	      size = gimple_call_arg (call, 2);
> > > > > > -	    ao_ref_init_from_ptr_and_size (&dref,
> > > > > > -					   gimple_call_arg (call, 1),
> > > > > > -					   size);
> > > > > > -	    return refs_may_alias_p_1 (&dref, ref, false);
> > > > > > -	  }
> > > > > > -	case BUILT_IN_BCOPY:
> > > > > > -	  {
> > > > > > -	    ao_ref dref;
> > > > > > -	    tree size = gimple_call_arg (call, 2);
> > > > > > -	    ao_ref_init_from_ptr_and_size (&dref,
> > > > > > -					   gimple_call_arg (call, 0),
> > > > > > -					   size);
> > > > > > -	    return refs_may_alias_p_1 (&dref, ref, false);
> > > > > > -	  }
> > > > > > -
> > > > > > -	/* The following functions read memory pointed to by their
> > > > > > -	   first argument.  */
> > > > > > -	CASE_BUILT_IN_TM_LOAD (1):
> > > > > > -	CASE_BUILT_IN_TM_LOAD (2):
> > > > > > -	CASE_BUILT_IN_TM_LOAD (4):
> > > > > > -	CASE_BUILT_IN_TM_LOAD (8):
> > > > > > -	CASE_BUILT_IN_TM_LOAD (FLOAT):
> > > > > > -	CASE_BUILT_IN_TM_LOAD (DOUBLE):
> > > > > > -	CASE_BUILT_IN_TM_LOAD (LDOUBLE):
> > > > > > -	CASE_BUILT_IN_TM_LOAD (M64):
> > > > > > -	CASE_BUILT_IN_TM_LOAD (M128):
> > > > > > -	CASE_BUILT_IN_TM_LOAD (M256):
> > > > > > -	case BUILT_IN_TM_LOG:
> > > > > > -	case BUILT_IN_TM_LOG_1:
> > > > > > -	case BUILT_IN_TM_LOG_2:
> > > > > > -	case BUILT_IN_TM_LOG_4:
> > > > > > -	case BUILT_IN_TM_LOG_8:
> > > > > > -	case BUILT_IN_TM_LOG_FLOAT:
> > > > > > -	case BUILT_IN_TM_LOG_DOUBLE:
> > > > > > -	case BUILT_IN_TM_LOG_LDOUBLE:
> > > > > > -	case BUILT_IN_TM_LOG_M64:
> > > > > > -	case BUILT_IN_TM_LOG_M128:
> > > > > > -	case BUILT_IN_TM_LOG_M256:
> > > > > > -	  return ptr_deref_may_alias_ref_p_1 (gimple_call_arg (call, 0), ref);
> > > > > > -
> > > > > > -	/* These read memory pointed to by the first argument.  */
> > > > > > -	case BUILT_IN_STRDUP:
> > > > > > -	case BUILT_IN_STRNDUP:
> > > > > > -	case BUILT_IN_REALLOC:
> > > > > > -	  {
> > > > > > -	    ao_ref dref;
> > > > > > -	    tree size = NULL_TREE;
> > > > > > -	    if (gimple_call_num_args (call) == 2)
> > > > > > -	      size = gimple_call_arg (call, 1);
> > > > > > -	    ao_ref_init_from_ptr_and_size (&dref,
> > > > > > -					   gimple_call_arg (call, 0),
> > > > > > -					   size);
> > > > > > -	    return refs_may_alias_p_1 (&dref, ref, false);
> > > > > > -	  }
> > > > > > -	/* These read memory pointed to by the first argument.  */
> > > > > > -	case BUILT_IN_INDEX:
> > > > > > -	case BUILT_IN_STRCHR:
> > > > > > -	case BUILT_IN_STRRCHR:
> > > > > > -	  {
> > > > > > -	    ao_ref dref;
> > > > > > -	    ao_ref_init_from_ptr_and_size (&dref,
> > > > > > -					   gimple_call_arg (call, 0),
> > > > > > -					   NULL_TREE);
> > > > > > -	    return refs_may_alias_p_1 (&dref, ref, false);
> > > > > > -	  }
> > > > > > -	/* These read memory pointed to by the first argument with size
> > > > > > -	   in the third argument.  */
> > > > > > -	case BUILT_IN_MEMCHR:
> > > > > > -	  {
> > > > > > -	    ao_ref dref;
> > > > > > -	    ao_ref_init_from_ptr_and_size (&dref,
> > > > > > -					   gimple_call_arg (call, 0),
> > > > > > -					   gimple_call_arg (call, 2));
> > > > > > -	    return refs_may_alias_p_1 (&dref, ref, false);
> > > > > > -	  }
> > > > > > -	/* These read memory pointed to by the first and second arguments.  */
> > > > > > -	case BUILT_IN_STRSTR:
> > > > > > -	case BUILT_IN_STRPBRK:
> > > > > > -	  {
> > > > > > -	    ao_ref dref;
> > > > > > -	    ao_ref_init_from_ptr_and_size (&dref,
> > > > > > -					   gimple_call_arg (call, 0),
> > > > > > -					   NULL_TREE);
> > > > > > -	    if (refs_may_alias_p_1 (&dref, ref, false))
> > > > > > -	      return true;
> > > > > > -	    ao_ref_init_from_ptr_and_size (&dref,
> > > > > > -					   gimple_call_arg (call, 1),
> > > > > > -					   NULL_TREE);
> > > > > > -	    return refs_may_alias_p_1 (&dref, ref, false);
> > > > > > -	  }
> > > > > > -
> > > > > > -	/* The following builtins do not read from memory.  */
> > > > > > -	case BUILT_IN_FREE:
> > > > > > -	case BUILT_IN_MALLOC:
> > > > > > -	case BUILT_IN_POSIX_MEMALIGN:
> > > > > > -	case BUILT_IN_ALIGNED_ALLOC:
> > > > > > -	case BUILT_IN_CALLOC:
> > > > > > -	CASE_BUILT_IN_ALLOCA:
> > > > > > -	case BUILT_IN_STACK_SAVE:
> > > > > > -	case BUILT_IN_STACK_RESTORE:
> > > > > > -	case BUILT_IN_MEMSET:
> > > > > > -	case BUILT_IN_TM_MEMSET:
> > > > > > -	case BUILT_IN_MEMSET_CHK:
> > > > > > -	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_SINCOS:
> > > > > > -	case BUILT_IN_SINCOSF:
> > > > > > -	case BUILT_IN_SINCOSL:
> > > > > > -	case BUILT_IN_ASSUME_ALIGNED:
> > > > > > -	case BUILT_IN_VA_END:
> > > > > > +      && gimple_call_builtin_p (call, BUILT_IN_NORMAL)
> > > > > > +      && (ao_classify_builtin (callee, &info)))
> > > > > > +    {
> > > > > > +      if (info.flags & AO_FUNCTION_BARRIER)
> > > > > > +	return true;
> > > > > > +      if (info.num_param_reads >= 0)
> > > > > > +	{
> > > > > > +	  for (int i = 0; i < info.num_param_reads; i++)
> > > > > > +	    {
> > > > > > +	      ao_ref dref;
> > > > > > +	      tree size = NULL_TREE;
> > > > > > +
> > > > > > +	      gcc_checking_assert (info.reads[i].size_param
> > > > > > +				   != info.reads[i].param);
> > > > > > +	      if (info.reads[i].size_param != -1)
> > > > > > +		size = gimple_call_arg (call, info.reads[i].size);
> > > > > > +	      else if (info.reads[i].size)
> > > > > > +		size = build_int_cst (size_type_node, info.reads[i].size);
> > > > > > +	      ao_ref_init_from_ptr_and_size (&dref,
> > > > > > +					     gimple_call_arg
> > > > > > +						 (call,
> > > > > > +						  info.reads[i].param),
> > > > > > +					     size);
> > > > > > +	      if (refs_may_alias_p_1 (&dref, ref, tbaa_p))
> > > > > > +		return true;
> > > > > > +	    }
> > > > > >  	  return false;
> > > > > > -	/* __sync_* builtins and some OpenMP builtins act as threading
> > > > > > -	   barriers.  */
> > > > > > -#undef DEF_SYNC_BUILTIN
> > > > > > -#define DEF_SYNC_BUILTIN(ENUM, NAME, TYPE, ATTRS) case ENUM:
> > > > > > -#include "sync-builtins.def"
> > > > > > -#undef DEF_SYNC_BUILTIN
> > > > > > -	case BUILT_IN_GOMP_ATOMIC_START:
> > > > > > -	case BUILT_IN_GOMP_ATOMIC_END:
> > > > > > -	case BUILT_IN_GOMP_BARRIER:
> > > > > > -	case BUILT_IN_GOMP_BARRIER_CANCEL:
> > > > > > -	case BUILT_IN_GOMP_TASKWAIT:
> > > > > > -	case BUILT_IN_GOMP_TASKGROUP_END:
> > > > > > -	case BUILT_IN_GOMP_CRITICAL_START:
> > > > > > -	case BUILT_IN_GOMP_CRITICAL_END:
> > > > > > -	case BUILT_IN_GOMP_CRITICAL_NAME_START:
> > > > > > -	case BUILT_IN_GOMP_CRITICAL_NAME_END:
> > > > > > -	case BUILT_IN_GOMP_LOOP_END:
> > > > > > -	case BUILT_IN_GOMP_LOOP_END_CANCEL:
> > > > > > -	case BUILT_IN_GOMP_ORDERED_START:
> > > > > > -	case BUILT_IN_GOMP_ORDERED_END:
> > > > > > -	case BUILT_IN_GOMP_SECTIONS_END:
> > > > > > -	case BUILT_IN_GOMP_SECTIONS_END_CANCEL:
> > > > > > -	case BUILT_IN_GOMP_SINGLE_COPY_START:
> > > > > > -	case BUILT_IN_GOMP_SINGLE_COPY_END:
> > > > > > -	  return true;
> > > > > > -
> > > > > > -	default:
> > > > > > -	  /* Fallthru to general call handling.  */;
> > > > > > -      }
> > > > > > +	}
> > > > > > +    }
> > > > > >  
> > > > > >    /* Check if base is a global static variable that is not read
> > > > > >       by the function.  */
> > > > > > @@ -2961,7 +3280,9 @@ call_may_clobber_ref_p_1 (gcall *call, ao_ref *ref, bool tbaa_p)
> > > > > >  	  modref_summary *summary = get_modref_function_summary (node);
> > > > > >  	  if (summary)
> > > > > >  	    {
> > > > > > -	      if (!modref_may_conflict (call, summary->stores, ref, tbaa_p))
> > > > > > +	      if (!modref_may_conflict (call, summary->stores, ref, tbaa_p)
> > > > > > +		  && (!summary->writes_errno
> > > > > > +		      || !targetm.ref_may_alias_errno (ref)))
> > > > > >  		{
> > > > > >  		  alias_stats.modref_clobber_no_alias++;
> > > > > >  		  if (dump_file && (dump_flags & TDF_DETAILS))
> > > > > > @@ -3016,205 +3337,43 @@ call_may_clobber_ref_p_1 (gcall *call, ao_ref *ref, bool tbaa_p)
> > > > > >        && SSA_NAME_POINTS_TO_READONLY_MEMORY (TREE_OPERAND (base, 0)))
> > > > > >      return false;
> > > > > >  
> > > > > > +  struct ao_function_info info;
> > > > > >    /* 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.  */
> > > > > > +     escape points.  */
> > > > > >    if (callee != NULL_TREE
> > > > > > -      && gimple_call_builtin_p (call, 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_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:
> > > > > > -	case BUILT_IN_MEMSET:
> > > > > > -	case BUILT_IN_TM_MEMSET:
> > > > > > -	CASE_BUILT_IN_TM_STORE (1):
> > > > > > -	CASE_BUILT_IN_TM_STORE (2):
> > > > > > -	CASE_BUILT_IN_TM_STORE (4):
> > > > > > -	CASE_BUILT_IN_TM_STORE (8):
> > > > > > -	CASE_BUILT_IN_TM_STORE (FLOAT):
> > > > > > -	CASE_BUILT_IN_TM_STORE (DOUBLE):
> > > > > > -	CASE_BUILT_IN_TM_STORE (LDOUBLE):
> > > > > > -	CASE_BUILT_IN_TM_STORE (M64):
> > > > > > -	CASE_BUILT_IN_TM_STORE (M128):
> > > > > > -	CASE_BUILT_IN_TM_STORE (M256):
> > > > > > -	case BUILT_IN_TM_MEMCPY:
> > > > > > -	case BUILT_IN_TM_MEMMOVE:
> > > > > > -	  {
> > > > > > -	    ao_ref dref;
> > > > > > -	    tree size = NULL_TREE;
> > > > > > -	    /* Don't pass in size for strncat, as the maximum size
> > > > > > -	       is strlen (dest) + n + 1 instead of n, resp.
> > > > > > -	       n + 1 at dest + strlen (dest), but strlen (dest) isn't
> > > > > > -	       known.  */
> > > > > > -	    if (gimple_call_num_args (call) == 3
> > > > > > -		&& DECL_FUNCTION_CODE (callee) != BUILT_IN_STRNCAT)
> > > > > > -	      size = gimple_call_arg (call, 2);
> > > > > > -	    ao_ref_init_from_ptr_and_size (&dref,
> > > > > > -					   gimple_call_arg (call, 0),
> > > > > > -					   size);
> > > > > > -	    return refs_may_alias_p_1 (&dref, ref, false);
> > > > > > -	  }
> > > > > > -	case BUILT_IN_STRCPY_CHK:
> > > > > > -	case BUILT_IN_STRNCPY_CHK:
> > > > > > -	case BUILT_IN_MEMCPY_CHK:
> > > > > > -	case BUILT_IN_MEMMOVE_CHK:
> > > > > > -	case BUILT_IN_MEMPCPY_CHK:
> > > > > > -	case BUILT_IN_STPCPY_CHK:
> > > > > > -	case BUILT_IN_STPNCPY_CHK:
> > > > > > -	case BUILT_IN_STRCAT_CHK:
> > > > > > -	case BUILT_IN_STRNCAT_CHK:
> > > > > > -	case BUILT_IN_MEMSET_CHK:
> > > > > > -	  {
> > > > > > -	    ao_ref dref;
> > > > > > -	    tree size = NULL_TREE;
> > > > > > -	    /* Don't pass in size for __strncat_chk, as the maximum size
> > > > > > -	       is strlen (dest) + n + 1 instead of n, resp.
> > > > > > -	       n + 1 at dest + strlen (dest), but strlen (dest) isn't
> > > > > > -	       known.  */
> > > > > > -	    if (gimple_call_num_args (call) == 4
> > > > > > -		&& DECL_FUNCTION_CODE (callee) != BUILT_IN_STRNCAT_CHK)
> > > > > > -	      size = gimple_call_arg (call, 2);
> > > > > > -	    ao_ref_init_from_ptr_and_size (&dref,
> > > > > > -					   gimple_call_arg (call, 0),
> > > > > > -					   size);
> > > > > > -	    return refs_may_alias_p_1 (&dref, ref, false);
> > > > > > -	  }
> > > > > > -	case BUILT_IN_BCOPY:
> > > > > > -	  {
> > > > > > -	    ao_ref dref;
> > > > > > -	    tree size = gimple_call_arg (call, 2);
> > > > > > -	    ao_ref_init_from_ptr_and_size (&dref,
> > > > > > -					   gimple_call_arg (call, 1),
> > > > > > -					   size);
> > > > > > -	    return refs_may_alias_p_1 (&dref, ref, false);
> > > > > > -	  }
> > > > > > -	/* Allocating memory does not have any side-effects apart from
> > > > > > -	   being the definition point for the pointer.  */
> > > > > > -	case BUILT_IN_MALLOC:
> > > > > > -	case BUILT_IN_ALIGNED_ALLOC:
> > > > > > -	case BUILT_IN_CALLOC:
> > > > > > -	case BUILT_IN_STRDUP:
> > > > > > -	case BUILT_IN_STRNDUP:
> > > > > > -	  /* Unix98 specifies that errno is set on allocation failure.  */
> > > > > > -	  if (flag_errno_math
> > > > > > -	      && targetm.ref_may_alias_errno (ref))
> > > > > > -	    return true;
> > > > > > -	  return false;
> > > > > > -	case BUILT_IN_STACK_SAVE:
> > > > > > -	CASE_BUILT_IN_ALLOCA:
> > > > > > -	case BUILT_IN_ASSUME_ALIGNED:
> > > > > > +      && gimple_call_builtin_p (call, BUILT_IN_NORMAL)
> > > > > > +      && (ao_classify_builtin (callee, &info)))
> > > > > > +    {
> > > > > > +      if (info.flags & AO_FUNCTION_BARRIER)
> > > > > > +	return true;
> > > > > > +      if ((info.flags & AO_FUNCTION_ERRNO)
> > > > > > +	  && flag_errno_math
> > > > > > +	  && targetm.ref_may_alias_errno (ref))
> > > > > > +	return true;
> > > > > > +      if (info.num_param_writes >= 0)
> > > > > > +	{
> > > > > > +	  for (int i = 0; i < info.num_param_writes; i++)
> > > > > > +	    {
> > > > > > +	      ao_ref dref;
> > > > > > +	      tree size = NULL_TREE;
> > > > > > +
> > > > > > +	      gcc_checking_assert (info.writes[i].size_param
> > > > > > +				   != info.writes[i].param);
> > > > > > +	      if (info.writes[i].size_param != -1)
> > > > > > +		size = gimple_call_arg (call, info.writes[i].size_param);
> > > > > > +	      else if (info.writes[i].size)
> > > > > > +		size = build_int_cst (size_type_node, info.writes[i].size);
> > > > > > +	      ao_ref_init_from_ptr_and_size (&dref,
> > > > > > +					     gimple_call_arg
> > > > > > +						 (call,
> > > > > > +						  info.writes[i].param),
> > > > > > +					     size);
> > > > > > +	      if (refs_may_alias_p_1 (&dref, ref, tbaa_p))
> > > > > > +		return true;
> > > > > > +	    }
> > > > > >  	  return false;
> > > > > > -	/* But posix_memalign stores a pointer into the memory pointed to
> > > > > > -	   by its first argument.  */
> > > > > > -	case BUILT_IN_POSIX_MEMALIGN:
> > > > > > -	  {
> > > > > > -	    tree ptrptr = gimple_call_arg (call, 0);
> > > > > > -	    ao_ref dref;
> > > > > > -	    ao_ref_init_from_ptr_and_size (&dref, ptrptr,
> > > > > > -					   TYPE_SIZE_UNIT (ptr_type_node));
> > > > > > -	    return (refs_may_alias_p_1 (&dref, ref, false)
> > > > > > -		    || (flag_errno_math
> > > > > > -			&& targetm.ref_may_alias_errno (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.  */
> > > > > > -	case BUILT_IN_FREE:
> > > > > > -	case BUILT_IN_VA_END:
> > > > > > -	  {
> > > > > > -	    tree ptr = gimple_call_arg (call, 0);
> > > > > > -	    return ptr_deref_may_alias_ref_p_1 (ptr, ref);
> > > > > > -	  }
> > > > > > -	/* Realloc serves both as allocation point and deallocation point.  */
> > > > > > -	case BUILT_IN_REALLOC:
> > > > > > -	  {
> > > > > > -	    tree ptr = gimple_call_arg (call, 0);
> > > > > > -	    /* Unix98 specifies that errno is set on allocation failure.  */
> > > > > > -	    return ((flag_errno_math
> > > > > > -		     && targetm.ref_may_alias_errno (ref))
> > > > > > -		    || ptr_deref_may_alias_ref_p_1 (ptr, ref));
> > > > > > -	  }
> > > > > > -	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:
> > > > > > -	  {
> > > > > > -	    tree out = gimple_call_arg (call, 1);
> > > > > > -	    if (ptr_deref_may_alias_ref_p_1 (out, ref))
> > > > > > -	      return true;
> > > > > > -	    if (flag_errno_math)
> > > > > > -	      break;
> > > > > > -	    return false;
> > > > > > -	  }
> > > > > > -	case BUILT_IN_FREXP:
> > > > > > -	case BUILT_IN_FREXPF:
> > > > > > -	case BUILT_IN_FREXPL:
> > > > > > -	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_1 (out, ref);
> > > > > > -	  }
> > > > > > -	case BUILT_IN_REMQUO:
> > > > > > -	case BUILT_IN_REMQUOF:
> > > > > > -	case BUILT_IN_REMQUOL:
> > > > > > -	  {
> > > > > > -	    tree out = gimple_call_arg (call, 2);
> > > > > > -	    if (ptr_deref_may_alias_ref_p_1 (out, ref))
> > > > > > -	      return true;
> > > > > > -	    if (flag_errno_math)
> > > > > > -	      break;
> > > > > > -	    return false;
> > > > > > -	  }
> > > > > > -	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);
> > > > > > -	    return (ptr_deref_may_alias_ref_p_1 (sin, ref)
> > > > > > -		    || ptr_deref_may_alias_ref_p_1 (cos, ref));
> > > > > > -	  }
> > > > > > -	/* __sync_* builtins and some OpenMP builtins act as threading
> > > > > > -	   barriers.  */
> > > > > > -#undef DEF_SYNC_BUILTIN
> > > > > > -#define DEF_SYNC_BUILTIN(ENUM, NAME, TYPE, ATTRS) case ENUM:
> > > > > > -#include "sync-builtins.def"
> > > > > > -#undef DEF_SYNC_BUILTIN
> > > > > > -	case BUILT_IN_GOMP_ATOMIC_START:
> > > > > > -	case BUILT_IN_GOMP_ATOMIC_END:
> > > > > > -	case BUILT_IN_GOMP_BARRIER:
> > > > > > -	case BUILT_IN_GOMP_BARRIER_CANCEL:
> > > > > > -	case BUILT_IN_GOMP_TASKWAIT:
> > > > > > -	case BUILT_IN_GOMP_TASKGROUP_END:
> > > > > > -	case BUILT_IN_GOMP_CRITICAL_START:
> > > > > > -	case BUILT_IN_GOMP_CRITICAL_END:
> > > > > > -	case BUILT_IN_GOMP_CRITICAL_NAME_START:
> > > > > > -	case BUILT_IN_GOMP_CRITICAL_NAME_END:
> > > > > > -	case BUILT_IN_GOMP_LOOP_END:
> > > > > > -	case BUILT_IN_GOMP_LOOP_END_CANCEL:
> > > > > > -	case BUILT_IN_GOMP_ORDERED_START:
> > > > > > -	case BUILT_IN_GOMP_ORDERED_END:
> > > > > > -	case BUILT_IN_GOMP_SECTIONS_END:
> > > > > > -	case BUILT_IN_GOMP_SECTIONS_END_CANCEL:
> > > > > > -	case BUILT_IN_GOMP_SINGLE_COPY_START:
> > > > > > -	case BUILT_IN_GOMP_SINGLE_COPY_END:
> > > > > > -	  return true;
> > > > > > -	default:
> > > > > > -	  /* Fallthru to general call handling.  */;
> > > > > > -      }
> > > > > > +	}
> > > > > > +    }
> > > > > >  
> > > > > >    /* Check if base is a global static variable that is not written
> > > > > >       by the function.  */
> > > > > > 
> > > > > 
> > > > > -- 
> > > > > Richard Biener <rguenther@suse.de>
> > > > > SUSE Software Solutions Germany GmbH, Maxfeldstrasse 5, 90409 Nuernberg,
> > > > > Germany; GF: Felix Imend
> > > > 
> > > > 
> > > 
> > > -- 
> > > Richard Biener <rguenther@suse.de>
> > > SUSE Software Solutions Germany GmbH, Maxfeldstrasse 5, 90409 Nuernberg,
> > > Germany; GF: Felix Imend
> > 
> > 
> 
> -- 
> Richard Biener <rguenther@suse.de>
> SUSE Software Solutions Germany GmbH, Maxfeldstrasse 5, 90409 Nuernberg,
> Germany; GF: Felix Imend
Richard Biener Sept. 28, 2020, 11:07 a.m. UTC | #7
On Mon, 28 Sep 2020, Jan Hubicka wrote:

> > On Mon, 28 Sep 2020, Jan Hubicka wrote:
> > 
> > > > 
> > > > Hmm, no - it expects the gimple_call_use/clobber_set to include
> > > > actions of the called function itself (const functions none here)
> > > > but for passed-by-value the loads may be in the call itself
> > > > which is where it uses gimple_call_arg_flags to skip unused ones.
> > > > 
> > > > But note that PTA uses gimple_call_arg_flags to compute
> > > > the gimple_call_use/clobber_set (but only in IPA mode) and the individual 
> > > > BUILT_IN_* handlings in tree-ssa-alias.c do what PTA would do
> > > > here, just directly as alias queries.  Originally I tried adding
> > > > "fn spec"s to BUILT_IN_* decls but that got out-of-hands ...
> > > 
> > > Yep, I was also looking into that, it looks ugly and moreover the
> > > attributes that depend on flag_math_errno and friends does not really
> > > work for function speicfic attributes, so it is bug we handle them this
> > > way.
> > > 
> > > Packing this into descriptor string in fnspec rather than descriptor
> > > sturcture returned on side works for me (and we could add them to thinws
> > > like C++ toplevel new/delete operator)
> > > > 
> > > > For example
> > > > 
> > > >         /* All the following functions read memory pointed to by
> > > >            their second argument.  strcat/strncat additionally
> > > >            reads memory pointed to by the first argument.  */
> > > >         case BUILT_IN_STRCAT:
> > > >         case BUILT_IN_STRNCAT:
> > > >           {
> > > >             ao_ref dref;
> > > >             ao_ref_init_from_ptr_and_size (&dref,
> > > >                                            gimple_call_arg (call, 0),
> > > >                                            NULL_TREE);
> > > >             if (refs_may_alias_p_1 (&dref, ref, false))
> > > >               return true;
> > > >           }
> > > > 
> > > > would be covered by "1WR" (W also implies read).  So the question
> > > > would be whether at least parts of your patch could be implemented
> > > > by making gimple_call_fnspec () return pre-determined fn-specs
> > > > for BUILT_IN_* (like we do with internal_fn_fnspec).
> > > 
> > > One important change would be that we still need to figure out if the
> > > function has other side effects.  Currently ref_maybe_used_by_call_p_1
> > > first tries to prove that ref is local and can not be used by the
> > > function unless it is passed as parameter value and then it looks into
> > > fnspec if the parameter is used.
> > > 
> > > For builtins it constructs tests based on the builtin type and bypasses
> > > the rest since it knows that all side effects are understood.
> > > 
> > > As far as I can tell, fn spec isused only by fortran for library calls,
> > > so perhaps it would not be too hard to turn fn spec semantics from "some
> > > properties of parameter handling are known" to "all memory accesses are
> > > known" or have additional way to indicate this.
> > 
> > Yeah, currently "fn spec" only says we know everything with respect
> > to a specific parameter but not the whole function.  We'd naturally
> > say the function is 'const' besides what specified by "fn spec" but
> > of course we cannot really use 'const' for this how.
> > 
> > > I guess space in return value predictor could be reserved for this, or
> > > we could have extra flags section at the begining.
> > 
> > Yeah, I think we want pure/const/unknown, so p,c,u with
> > upper case denoting 'errno' is clobbered (eh...).
> 
> Sounds good to me
> > 
> > > > 
> > > > >  We would need
> > > > > to invent how to add info that non pure/const function only access the
> > > > > argument according to fn spec, add way to represent sizes of accesses
> > > > > and how to handle errno.
> > > > 
> > > > True - fn-spec lacks an ability to specify access size - fortunately
> > > > it's internal and we could change it ;)  Whether or not sth can clobber
> > > > errno is sth we eventually need to move to the stmt level anyway
> > > > (-f[no-]math-errno crossing inline boundary) - bit sad to waste a
> > > > bit in a gimple call for this though.  OTOH we waste a ton of space
> > > > in the call_used/call_clobbered members due to bad packing
> > > > (unsigned int bitfield followed by a pointer to a bitmap).  Eventually
> > > > we could offload this kind of info from the main stmt.  We could
> > > > also allocate a fake UID to represent errno (but then the rest of
> > > > the bits in call_used/call_clobbered have to be precise) - but note
> > > > call_used/call_clobbered does not transfer during inlining.
> > > > 
> > > > So for the access size issue we could blow up fnspec by factor of two,
> > > > reserving two chars per argument/return value and do
> > > > 
> > > >  1.W3R.
> > > 
> > > We also have known bytesizes like return values of sincos
> > > (where the size really matters on the size of type that is known only at
> > > runtime).
> > > That can be 3 digits if represented decimally (or two digits hex, but
> > > it may become too small in future with vector types)
> > 
> > Hmm, we can use Wt for 'formal argument type', so sincos 'double *'
> > would mean 'double'?  Not sure if that's enough for all cases.
> 
> We currently handle only sincos and memalign, but there are also things
> like tm load/store builtins that could do the same.
> > 
> > > One option would be make the unit to be the size of pointer pointed to,
> > > tat would turn it to be 1 in all cases we handle. Then we could blow up
> > > by 3 and have something like P1 meaning "size is described by parameter
> > > numer 1" and "10" meaning 10 elements are written by the function.
> > 
> > So for the case we have int * and int n parameter and the size is
> > n * sizeof (int) you mean?  Do we have this complicated cases for
> > builtins?  We could also add some escape mechanism (double-ick),
> In the two examples handled this is always 1.  But I wonder if vector
> builtins would fit naturally to that.
> > like Wl 'literal' meaning the actual value is appended to the
> > fn spec.  Thus int foo (int *p, unsigned) writing 54 items to *p
> > would be ..Wl..54 ... (and L for 4-char literal).  For scaling
> > by typeof (*p) we could use a-z instead of 1-9 to refer to the
> > parameter in question.  So yeah, it gets a bit fugly if overloaded
> > too heavily.
> 
> Since I think fn spec are yours, it would be great if you could write me
> a short spec on the semantics of the string and I could imlement it.

OK, so lets blow up slots to two chars, the second char of the return
slot shall be

  'c' - function is otherwise 'const'
  'p' - function is otherwise 'pure'
  'C' - function is otherwise 'const' but may clobber errno
  'P' - function is otherwise 'pure' but may clobber errno
  '.' - function reads/writes random memory (but through parameters
        only as specified unless the passed memory already escaped
        by other means), current behavior

in particular current behavior means that specifying ..W for
foo (int *) called like

void bar()
{
  int l = 1;
  foo (&l);
  if (l != 5)
    abort ();
}

would be OK but when disambiguating the 'l' load against the
call we need to check whether it aliases a dereference of &l
because 'l' isn't considered global memory (it doesn't escape
thanks to the 'W' constraint).  PTA makes sure to add 'l' to
the clobber set at the point it elides putting 'l' into ESCAPED.

For argument slots we have the current flags in the first
character position.  We add

  '1'-'9' - object is read/write directly N bytes as specified by arg 1-9
  't' - object is read/write directly N bytes as specified by the pointer
        argument type

that's all I'd add today.  I'd probably do the blow up to two chars
without actually putting the 2nd char to use as preparatory patch
to catch all existing fnspec builts.  And maybe abstract the
build_string (len, "...") that's used to a build_fnspec_string ()
to be able to more easily find them ;)  Or in case all callers
are very similar even put the tree list building into the abstraction
and make it append_fnspec_attribute ().  Looks like it's really
only used by the fortran FE and a very few select builtins
(ATTR_RET1_NOTHROW_NONNULL_LEAF) where I think the current string
works fine.

Richard.

> Honza
> > 
> > > > for strncat plus add gimple_call_arg_size to access it.  The 2nd
> > > > slot in return value could host the errno thing (eh).
> > > > 
> > > >  .e
> > > > 
> > > > for sqrt for example.
> > > > 
> > > > Just to repeat again - the info looks too similar to warrant an
> > > > extra mechanism to record it.
> > > 
> > > No problem, just if we figure way to do so :)
> > 
> > Yes indeed.
> > 
> > Richard.
> > 
> > > > 
> > > > Richard.
> > > > 
> > > > > Honza
> > > > > > 
> > > > > > > gcc/ChangeLog:
> > > > > > > 
> > > > > > > 2020-09-28  Jan Hubicka  <hubicka@ucw.cz>
> > > > > > > 
> > > > > > > 	* tree-ssa-alias.c (ao_classify_builtin): New function commonizing
> > > > > > > 	logic from ...
> > > > > > > 	(ref_maybe_used_by_call_p_1): ... here.
> > > > > > > 	(call_may_clobber_ref_p_1): ... and here.
> > > > > > > 	* tree-ssa-alias.h (enum ao_function_flags): New enum.
> > > > > > > 	(struct ao_function_info): New structure.
> > > > > > > 	(ao_classify_builtin): Declare.
> > > > > > > 
> > > > > > > diff --git a/gcc/tree-ssa-alias.h b/gcc/tree-ssa-alias.h
> > > > > > > index 1dd02c0ea62..eecb8da6dd7 100644
> > > > > > > --- a/gcc/tree-ssa-alias.h
> > > > > > > +++ b/gcc/tree-ssa-alias.h
> > > > > > > @@ -108,6 +108,33 @@ ao_ref::max_size_known_p () const
> > > > > > >    return known_size_p (max_size);
> > > > > > >  }
> > > > > > >  
> > > > > > > +/* Flags used in ao_function_info.  */
> > > > > > > +
> > > > > > > +enum ao_function_flags
> > > > > > > +{
> > > > > > > +  AO_FUNCTION_BARRIER = 1,
> > > > > > > +  AO_FUNCTION_ERRNO = 2,
> > > > > > > +};
> > > > > > > +
> > > > > > > +/* Describe side effects relevant for alias analysis of function call to
> > > > > > > +   DECL.  */
> > > > > > > +
> > > > > > > +struct ao_function_info
> > > > > > > +{
> > > > > > > +  int num_param_reads;  /* Number of parameters function reads from,
> > > > > > > +			   -1 if reads are unknown.  */
> > > > > > > +  struct ao_access_info
> > > > > > > +    {
> > > > > > > +      char param; 	/* Index of parameter read/written from.  */
> > > > > > > +      char size_param;	/* Index of parameter specifying size of the access,
> > > > > > > +			   -1 if unknown.  */
> > > > > > > +      char size;	/* Size of access if known, 0 if unknown.  */
> > > > > > > +    } reads[2];
> > > > > > > +  int num_param_writes;
> > > > > > > +  struct ao_access_info writes[2];
> > > > > > > +  enum ao_function_flags flags;
> > > > > > > +};
> > > > > > > +
> > > > > > >  /* In tree-ssa-alias.c  */
> > > > > > >  extern void ao_ref_init (ao_ref *, tree);
> > > > > > >  extern void ao_ref_init_from_ptr_and_size (ao_ref *, tree, tree);
> > > > > > > @@ -158,6 +185,7 @@ extern void debug (pt_solution *ptr);
> > > > > > >  extern void dump_points_to_info_for (FILE *, tree);
> > > > > > >  extern void debug_points_to_info_for (tree);
> > > > > > >  extern void dump_alias_stats (FILE *);
> > > > > > > +extern bool ao_classify_builtin (tree callee, ao_function_info *info);
> > > > > > >  
> > > > > > >  
> > > > > > >  /* In tree-ssa-structalias.c  */
> > > > > > > diff --git a/gcc/tree-ssa-alias.c b/gcc/tree-ssa-alias.c
> > > > > > > index fe390d4ffbe..c182e7bb39c 100644
> > > > > > > --- a/gcc/tree-ssa-alias.c
> > > > > > > +++ b/gcc/tree-ssa-alias.c
> > > > > > > @@ -2503,6 +2503,507 @@ modref_may_conflict (const gimple *stmt,
> > > > > > >    return false;
> > > > > > >  }
> > > > > > >  
> > > > > > > +/* If CALLEE has known side effects, fill in INFO and return true.
> > > > > > > +   See tree-ssa-structalias.c:find_func_aliases
> > > > > > > +   for the list of builtins we might need to handle here.  */
> > > > > > > +
> > > > > > > +bool
> > > > > > > +ao_classify_builtin (tree callee, ao_function_info *info)
> > > > > > > +{
> > > > > > > +  built_in_function code = DECL_FUNCTION_CODE (callee);
> > > > > > > +
> > > > > > > +  switch (code)
> > > > > > > +    {
> > > > > > > +      /* All the following functions read memory pointed to by
> > > > > > > +	 their second argument and write memory pointed to by first
> > > > > > > +	 argument.
> > > > > > > +	 strcat/strncat additionally reads memory pointed to by the first
> > > > > > > +	 argument.  */
> > > > > > > +      case BUILT_IN_STRCAT:
> > > > > > > +	{
> > > > > > > +	  const static struct ao_function_info ret_info
> > > > > > > +	       = {
> > > > > > > +		    2,				/* num_param_reads.  */
> > > > > > > +
> > > > > > > +		    /* Reads and write descriptors are triples containing:
> > > > > > > +		       - index of parameter read
> > > > > > > +		       - index of parameter specifying access size
> > > > > > > +			 (-1 if unknown)
> > > > > > > +		       - access size in bytes (0 if unkown).  */
> > > > > > > +
> > > > > > > +		    {{0, -1, 0}, {1, -1, 0}},	/* Param read.  */
> > > > > > > +		    1,				/* num_param_writes.  */
> > > > > > > +		    {{0, -1, 0}},		/* Param written.  */
> > > > > > > +		    (ao_function_flags)0,	/* flags.  */
> > > > > > > +		 };
> > > > > > > +	  *info = ret_info;
> > > > > > > +	  return true;
> > > > > > > +	}
> > > > > > > +      case BUILT_IN_STRNCAT:
> > > > > > > +	{
> > > > > > > +	  const static struct ao_function_info ret_info
> > > > > > > +	       = {
> > > > > > > +		    2,				/* num_param_reads.  */
> > > > > > > +		    {{0, -1, 0}, {1, 2, 0}},	/* Param read.  */
> > > > > > > +		    1,				/* num_param_writes.  */
> > > > > > > +		    {{0, -1, 0}},		/* Param written.  */
> > > > > > > +		    (ao_function_flags)0,	/* flags.  */
> > > > > > > +		 };
> > > > > > > +	  *info = ret_info;
> > > > > > > +	  return true;
> > > > > > > +	}
> > > > > > > +      case BUILT_IN_STRCPY:
> > > > > > > +      case BUILT_IN_STPCPY:
> > > > > > > +	{
> > > > > > > +	  const static struct ao_function_info ret_info
> > > > > > > +	       = {
> > > > > > > +		    1,				/* num_param_reads.  */
> > > > > > > +		    {{1, -1, 0}},		/* Param read.  */
> > > > > > > +		    1,				/* num_param_writes.  */
> > > > > > > +		    {{0, -1, 0}},		/* Param written.  */
> > > > > > > +		    (ao_function_flags)0,	/* flags.  */
> > > > > > > +		 };
> > > > > > > +	  *info = ret_info;
> > > > > > > +	  return true;
> > > > > > > +	}
> > > > > > > +      case BUILT_IN_STRNCPY:
> > > > > > > +      case BUILT_IN_MEMCPY:
> > > > > > > +      case BUILT_IN_MEMMOVE:
> > > > > > > +      case BUILT_IN_MEMPCPY:
> > > > > > > +      case BUILT_IN_STPNCPY:
> > > > > > > +      case BUILT_IN_TM_MEMCPY:
> > > > > > > +      case BUILT_IN_TM_MEMMOVE:
> > > > > > > +	{
> > > > > > > +	  const static struct ao_function_info ret_info
> > > > > > > +	       = {
> > > > > > > +		    1,				/* num_param_reads.  */
> > > > > > > +		    {{1, 2, 0}},		/* Param read.  */
> > > > > > > +		    1,				/* num_param_writes.  */
> > > > > > > +		    {{0, 2, 0}},		/* Param written.  */
> > > > > > > +		    (ao_function_flags)0,	/* flags.  */
> > > > > > > +		 };
> > > > > > > +	  *info = ret_info;
> > > > > > > +	  return true;
> > > > > > > +	}
> > > > > > > +      case BUILT_IN_STRCAT_CHK:
> > > > > > > +	{
> > > > > > > +	  const static struct ao_function_info ret_info
> > > > > > > +	       = {
> > > > > > > +		    2,				/* num_param_reads.  */
> > > > > > > +		    {{0, -1, 0}, {1, -1, 0}},	/* Param read.  */
> > > > > > > +		    1,				/* num_param_writes.  */
> > > > > > > +		    {{0, -1, 0}},		/* Param written.  */
> > > > > > > +		    (ao_function_flags)0,	/* flags.  */
> > > > > > > +		 };
> > > > > > > +	  *info = ret_info;
> > > > > > > +	  return true;
> > > > > > > +	}
> > > > > > > +      case BUILT_IN_STRNCAT_CHK:
> > > > > > > +	{
> > > > > > > +	  const static struct ao_function_info ret_info
> > > > > > > +	       = {
> > > > > > > +		    2,				/* num_param_reads.  */
> > > > > > > +		    {{0, -1, 0}, {1, 2, 0}},	/* Param read.  */
> > > > > > > +		    1,				/* num_param_writes.  */
> > > > > > > +		    {{0, -1, 0}},		/* Param written.  */
> > > > > > > +		    (ao_function_flags)0,	/* flags.  */
> > > > > > > +		 };
> > > > > > > +	  *info = ret_info;
> > > > > > > +	  return true;
> > > > > > > +	}
> > > > > > > +      case BUILT_IN_STRCPY_CHK:
> > > > > > > +      case BUILT_IN_STPCPY_CHK:
> > > > > > > +	{
> > > > > > > +	  const static struct ao_function_info ret_info
> > > > > > > +	       = {
> > > > > > > +		    1,				/* num_param_reads.  */
> > > > > > > +		    {{1, -1, 0}},		/* Param read.  */
> > > > > > > +		    1,				/* num_param_writes.  */
> > > > > > > +		    {{0, -1, 0}},		/* Param written.  */
> > > > > > > +		    (ao_function_flags)0,	/* flags.  */
> > > > > > > +		 };
> > > > > > > +	  *info = ret_info;
> > > > > > > +	  return true;
> > > > > > > +	}
> > > > > > > +      case BUILT_IN_STRNCPY_CHK:
> > > > > > > +      case BUILT_IN_MEMCPY_CHK:
> > > > > > > +      case BUILT_IN_MEMMOVE_CHK:
> > > > > > > +      case BUILT_IN_MEMPCPY_CHK:
> > > > > > > +      case BUILT_IN_STPNCPY_CHK:
> > > > > > > +	{
> > > > > > > +	  const static struct ao_function_info ret_info
> > > > > > > +	       = {
> > > > > > > +		    1,				/* num_param_reads.  */
> > > > > > > +		    {{1, 2, 0}},		/* Param read.  */
> > > > > > > +		    1,				/* num_param_writes.  */
> > > > > > > +		    {{0, 2, 0}},		/* Param written.  */
> > > > > > > +		    (ao_function_flags)0,	/* flags.  */
> > > > > > > +		 };
> > > > > > > +	  *info = ret_info;
> > > > > > > +	  return true;
> > > > > > > +	}
> > > > > > > +      case BUILT_IN_BCOPY:
> > > > > > > +	{
> > > > > > > +	  const static struct ao_function_info ret_info
> > > > > > > +	       = {
> > > > > > > +		    1,				/* num_param_reads.  */
> > > > > > > +		    {{0, 2, 0}},		/* Param read.  */
> > > > > > > +		    1,				/* num_param_writes.  */
> > > > > > > +		    {{1, 2, 0}},		/* Param written.  */
> > > > > > > +		    (ao_function_flags)0,	/* flags.  */
> > > > > > > +		 };
> > > > > > > +	  *info = ret_info;
> > > > > > > +	  return true;
> > > > > > > +	}
> > > > > > > +
> > > > > > > +      /* The following functions read memory pointed to by their
> > > > > > > +	 first argument.  */
> > > > > > > +      CASE_BUILT_IN_TM_LOAD (1):
> > > > > > > +      CASE_BUILT_IN_TM_LOAD (2):
> > > > > > > +      CASE_BUILT_IN_TM_LOAD (4):
> > > > > > > +      CASE_BUILT_IN_TM_LOAD (8):
> > > > > > > +      CASE_BUILT_IN_TM_LOAD (FLOAT):
> > > > > > > +      CASE_BUILT_IN_TM_LOAD (DOUBLE):
> > > > > > > +      CASE_BUILT_IN_TM_LOAD (LDOUBLE):
> > > > > > > +      CASE_BUILT_IN_TM_LOAD (M64):
> > > > > > > +      CASE_BUILT_IN_TM_LOAD (M128):
> > > > > > > +      CASE_BUILT_IN_TM_LOAD (M256):
> > > > > > > +      case BUILT_IN_TM_LOG:
> > > > > > > +      case BUILT_IN_TM_LOG_1:
> > > > > > > +      case BUILT_IN_TM_LOG_2:
> > > > > > > +      case BUILT_IN_TM_LOG_4:
> > > > > > > +      case BUILT_IN_TM_LOG_8:
> > > > > > > +      case BUILT_IN_TM_LOG_FLOAT:
> > > > > > > +      case BUILT_IN_TM_LOG_DOUBLE:
> > > > > > > +      case BUILT_IN_TM_LOG_LDOUBLE:
> > > > > > > +      case BUILT_IN_TM_LOG_M64:
> > > > > > > +      case BUILT_IN_TM_LOG_M128:
> > > > > > > +      case BUILT_IN_TM_LOG_M256:
> > > > > > > +
> > > > > > > +      case BUILT_IN_INDEX:
> > > > > > > +      case BUILT_IN_STRCHR:
> > > > > > > +      case BUILT_IN_STRRCHR:
> > > > > > > +	{
> > > > > > > +	  const static struct ao_function_info ret_info
> > > > > > > +	       = {
> > > > > > > +		    1,				/* num_param_reads.  */
> > > > > > > +		    /* TODO: For TM builtins size is known.  */
> > > > > > > +		    {{0, -1, 0}},		/* Param read.  */
> > > > > > > +		    0,				/* num_param_writes.  */
> > > > > > > +		    {},				/* Param written.  */
> > > > > > > +		    (ao_function_flags)0,	/* flags.  */
> > > > > > > +		 };
> > > > > > > +	  *info = ret_info;
> > > > > > > +	  return true;
> > > > > > > +	}
> > > > > > > +
> > > > > > > +      /* These read memory pointed to by the first argument.
> > > > > > > +	 Allocating memory does not have any side-effects apart from
> > > > > > > +	 being the definition point for the pointer.
> > > > > > > +	 Unix98 specifies that errno is set on allocation failure.  */
> > > > > > > +      case BUILT_IN_STRDUP:
> > > > > > > +	{
> > > > > > > +	  const static struct ao_function_info ret_info
> > > > > > > +	       = {
> > > > > > > +		    1,				/* num_param_reads.  */
> > > > > > > +		    {{0, -1, 0}},		/* Param read.  */
> > > > > > > +		    0,				/* num_param_writes.  */
> > > > > > > +		    {},				/* Param written.  */
> > > > > > > +		    AO_FUNCTION_ERRNO,		/* flags.  */
> > > > > > > +		 };
> > > > > > > +	  *info = ret_info;
> > > > > > > +	  return true;
> > > > > > > +	}
> > > > > > > +      case BUILT_IN_STRNDUP:
> > > > > > > +	{
> > > > > > > +	  const static struct ao_function_info ret_info
> > > > > > > +	       = {
> > > > > > > +		    1,				/* num_param_reads.  */
> > > > > > > +		    {{0, 1, 0}},		/* Param read.  */
> > > > > > > +		    0,				/* num_param_writes.  */
> > > > > > > +		    {},				/* Param written.  */
> > > > > > > +		    AO_FUNCTION_ERRNO,		/* flags.  */
> > > > > > > +		 };
> > > > > > > +	  *info = ret_info;
> > > > > > > +	  return true;
> > > > > > > +	}
> > > > > > > +      /* Allocating memory does not have any side-effects apart from
> > > > > > > +	 being the definition point for the pointer.  */
> > > > > > > +      case BUILT_IN_MALLOC:
> > > > > > > +      case BUILT_IN_ALIGNED_ALLOC:
> > > > > > > +      case BUILT_IN_CALLOC:
> > > > > > > +	{
> > > > > > > +	  const static struct ao_function_info ret_info
> > > > > > > +	       = {
> > > > > > > +		    0,				/* num_param_reads.  */
> > > > > > > +		    {},				/* Param read.  */
> > > > > > > +		    0,				/* num_param_writes.  */
> > > > > > > +		    {},				/* Param written.  */
> > > > > > > +		    AO_FUNCTION_ERRNO,		/* flags.  */
> > > > > > > +		 };
> > > > > > > +	  *info = ret_info;
> > > > > > > +	  return true;
> > > > > > > +	}
> > > > > > > +      /* These read memory pointed to by the first argument with size
> > > > > > > +	 in the third argument.  */
> > > > > > > +      case BUILT_IN_MEMCHR:
> > > > > > > +	{
> > > > > > > +	  const static struct ao_function_info ret_info
> > > > > > > +	       = {
> > > > > > > +		    1,				/* num_param_reads.  */
> > > > > > > +		    {{0, 2, 0}},		/* Param read.  */
> > > > > > > +		    0,				/* num_param_writes.  */
> > > > > > > +		    {},				/* Param written.  */
> > > > > > > +		    (ao_function_flags)0,	/* flags.  */
> > > > > > > +		 };
> > > > > > > +	  *info = ret_info;
> > > > > > > +	  return true;
> > > > > > > +	}
> > > > > > > +      /* These read memory pointed to by the first and second arguments.  */
> > > > > > > +      case BUILT_IN_STRSTR:
> > > > > > > +      case BUILT_IN_STRPBRK:
> > > > > > > +	{
> > > > > > > +	  static struct ao_function_info ret_info
> > > > > > > +	       = {
> > > > > > > +		    2,				/* num_param_reads.  */
> > > > > > > +		    {{0, -1, 0}, {1, -1, 0}},	/* Param read.  */
> > > > > > > +		    0,				/* num_param_writes.  */
> > > > > > > +		    {},				/* Param written.  */
> > > > > > > +		    (ao_function_flags)0,	/* flags.  */
> > > > > > > +		 };
> > > > > > > +	  *info = ret_info;
> > > > > > > +	  return true;
> > > > > > > +	}
> > > > > > > +      /* Freeing memory kills the pointed-to memory.  More importantly
> > > > > > > +	 the call has to serve as a barrier for moving loads and stores
> > > > > > > +	 across it.  */
> > > > > > > +      case BUILT_IN_FREE:
> > > > > > > +      case BUILT_IN_VA_END:
> > > > > > > +	{
> > > > > > > +	  const static struct ao_function_info ret_info
> > > > > > > +	       = {
> > > > > > > +		    0,				/* num_param_reads.  */
> > > > > > > +		    {},				/* Param read.  */
> > > > > > > +		    1,				/* num_param_writes.  */
> > > > > > > +		    {{0, -1, 0}},		/* Param written.  */
> > > > > > > +		    (ao_function_flags)0,	/* flags.  */
> > > > > > > +		 };
> > > > > > > +	  *info = ret_info;
> > > > > > > +	  return true;
> > > > > > > +	}
> > > > > > > +      /* Realloc serves both as allocation point and deallocation point.  */
> > > > > > > +      case BUILT_IN_REALLOC:
> > > > > > > +	{
> > > > > > > +	  const static struct ao_function_info ret_info
> > > > > > > +	       = {
> > > > > > > +		    1,				/* num_param_reads.  */
> > > > > > > +		    {{0, 1, 0}},		/* Param read.  */
> > > > > > > +		    0,				/* num_param_writes.  */
> > > > > > > +		    {{0, -1, 0}},		/* Param written.  */
> > > > > > > +		    AO_FUNCTION_ERRNO,		/* flags.  */
> > > > > > > +		 };
> > > > > > > +	  *info = ret_info;
> > > > > > > +	  return true;
> > > > > > > +	}
> > > > > > > +      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:
> > > > > > > +	{
> > > > > > > +	  const static struct ao_function_info ret_info
> > > > > > > +	       = {
> > > > > > > +		    0,				/* num_param_reads.  */
> > > > > > > +		    {},				/* Param read.  */
> > > > > > > +		    1,				/* num_param_writes.  */
> > > > > > > +		    {{1, -1, 0}},		/* Param written.  */
> > > > > > > +		    AO_FUNCTION_ERRNO,		/* flags.  */
> > > > > > > +		 };
> > > > > > > +	  *info = ret_info;
> > > > > > > +	  return true;
> > > > > > > +	}
> > > > > > > +      case BUILT_IN_FREXP:
> > > > > > > +      case BUILT_IN_FREXPF:
> > > > > > > +      case BUILT_IN_FREXPL:
> > > > > > > +      case BUILT_IN_MODF:
> > > > > > > +      case BUILT_IN_MODFF:
> > > > > > > +      case BUILT_IN_MODFL:
> > > > > > > +	{
> > > > > > > +	  const static struct ao_function_info ret_info
> > > > > > > +	       = {
> > > > > > > +		    0,				/* num_param_reads.  */
> > > > > > > +		    {},				/* Param read.  */
> > > > > > > +		    1,				/* num_param_writes.  */
> > > > > > > +		    {{1, -1, 0}},		/* Param written.  */
> > > > > > > +		    (ao_function_flags)0,	/* flags.  */
> > > > > > > +		 };
> > > > > > > +	  *info = ret_info;
> > > > > > > +	  return true;
> > > > > > > +	}
> > > > > > > +      case BUILT_IN_REMQUO:
> > > > > > > +      case BUILT_IN_REMQUOF:
> > > > > > > +      case BUILT_IN_REMQUOL:
> > > > > > > +	{
> > > > > > > +	  const static struct ao_function_info ret_info
> > > > > > > +	       = {
> > > > > > > +		    0,				/* num_param_reads.  */
> > > > > > > +		    {},				/* Param read.  */
> > > > > > > +		    1,				/* num_param_writes.  */
> > > > > > > +		    {{2, -1, 0}},		/* Param written.  */
> > > > > > > +		    (ao_function_flags)0,	/* flags.  */
> > > > > > > +		 };
> > > > > > > +	  *info = ret_info;
> > > > > > > +	  return true;
> > > > > > > +	}
> > > > > > > +      case BUILT_IN_SINCOS:
> > > > > > > +      case BUILT_IN_SINCOSF:
> > > > > > > +      case BUILT_IN_SINCOSL:
> > > > > > > +	{
> > > > > > > +	  static struct ao_function_info ret_info
> > > > > > > +	       = {
> > > > > > > +		    0,				/* num_param_reads.  */
> > > > > > > +		    {},				/* Param read.  */
> > > > > > > +		    1,				/* num_param_writes.  */
> > > > > > > +		    {{1, -1, 0}, {2, -1, 0}},	/* Param written.  */
> > > > > > > +		    (ao_function_flags)0,	/* flags.  */
> > > > > > > +		 };
> > > > > > > +	  tree type = float_ptr_type_node;
> > > > > > > +	  if (code == BUILT_IN_SINCOS)
> > > > > > > +	    type = double_ptr_type_node;
> > > > > > > +	  else
> > > > > > > +	    type = long_double_ptr_type_node;
> > > > > > > +	  ret_info.writes[0].size = ret_info.writes[1].size
> > > > > > > +		 = tree_to_uhwi (TYPE_SIZE_UNIT (type));
> > > > > > > +	  *info = ret_info;
> > > > > > > +	  return true;
> > > > > > > +	}
> > > > > > > +      case BUILT_IN_MEMSET:
> > > > > > > +      case BUILT_IN_MEMSET_CHK:
> > > > > > > +      case BUILT_IN_TM_MEMSET:
> > > > > > > +	{
> > > > > > > +	  const static struct ao_function_info ret_info
> > > > > > > +	       = {
> > > > > > > +		    0,				/* num_param_reads.  */
> > > > > > > +		    {},				/* Param read.  */
> > > > > > > +		    1,				/* num_param_writes.  */
> > > > > > > +		    {0, 2, 0},			/* Param written.  */
> > > > > > > +		    (ao_function_flags)0,	/* flags.  */
> > > > > > > +		 };
> > > > > > > +	  *info = ret_info;
> > > > > > > +	  return true;
> > > > > > > +	}
> > > > > > > +      CASE_BUILT_IN_TM_STORE (1):
> > > > > > > +      CASE_BUILT_IN_TM_STORE (2):
> > > > > > > +      CASE_BUILT_IN_TM_STORE (4):
> > > > > > > +      CASE_BUILT_IN_TM_STORE (8):
> > > > > > > +      CASE_BUILT_IN_TM_STORE (FLOAT):
> > > > > > > +      CASE_BUILT_IN_TM_STORE (DOUBLE):
> > > > > > > +      CASE_BUILT_IN_TM_STORE (LDOUBLE):
> > > > > > > +      CASE_BUILT_IN_TM_STORE (M64):
> > > > > > > +      CASE_BUILT_IN_TM_STORE (M128):
> > > > > > > +      CASE_BUILT_IN_TM_STORE (M256):
> > > > > > > +	{
> > > > > > > +	  const static struct ao_function_info ret_info
> > > > > > > +	       = {
> > > > > > > +		    0,				/* num_param_reads.  */
> > > > > > > +		    {},				/* Param read.  */
> > > > > > > +		    1,				/* num_param_writes.  */
> > > > > > > +		    /* TODO: Size is known.  */
> > > > > > > +		    {0, -1, 0},			/* Param written.  */
> > > > > > > +		    (ao_function_flags)0,	/* flags.  */
> > > > > > > +		 };
> > > > > > > +	  *info = ret_info;
> > > > > > > +	  return true;
> > > > > > > +	}
> > > > > > > +      case BUILT_IN_STACK_SAVE:
> > > > > > > +      CASE_BUILT_IN_ALLOCA:
> > > > > > > +      case BUILT_IN_ASSUME_ALIGNED:
> > > > > > > +	{
> > > > > > > +	  const static struct ao_function_info ret_info
> > > > > > > +	       = {
> > > > > > > +		    0,				/* num_param_reads.  */
> > > > > > > +		    {},				/* Param read.  */
> > > > > > > +		    0,				/* num_param_writes.  */
> > > > > > > +		    {},				/* Param written.  */
> > > > > > > +		    (ao_function_flags)0,	/* flags.  */
> > > > > > > +		 };
> > > > > > > +	  *info = ret_info;
> > > > > > > +	  return true;
> > > > > > > +	}
> > > > > > > +      /* But posix_memalign stores a pointer into the memory pointed to
> > > > > > > +	 by its first argument.  */
> > > > > > > +      case BUILT_IN_POSIX_MEMALIGN:
> > > > > > > +	{
> > > > > > > +	  static struct ao_function_info ret_info
> > > > > > > +	       = {
> > > > > > > +		    0,				/* num_param_reads.  */
> > > > > > > +		    {},				/* Param read.  */
> > > > > > > +		    0,				/* num_param_writes.  */
> > > > > > > +		    {{0, -1, 0}},		/* Param written.  */
> > > > > > > +		    AO_FUNCTION_ERRNO,		/* flags.  */
> > > > > > > +		 };
> > > > > > > +	  ret_info.writes[0].size
> > > > > > > +		 = tree_to_uhwi (TYPE_SIZE_UNIT (ptr_type_node));
> > > > > > > +	  *info = ret_info;
> > > > > > > +	  return true;
> > > > > > > +	}
> > > > > > > +      /* The following builtins do not read from memory.  */
> > > > > > > +      case BUILT_IN_STACK_RESTORE:
> > > > > > > +	{
> > > > > > > +	  const static struct ao_function_info ret_info
> > > > > > > +	       = {
> > > > > > > +		    0,				/* num_param_reads.  */
> > > > > > > +		    {},				/* Param read.  */
> > > > > > > +		    0,				/* num_param_writes.  */
> > > > > > > +		    {},				/* Param written.  */
> > > > > > > +		    (ao_function_flags)0,	/* flags.  */
> > > > > > > +		 };
> > > > > > > +	  *info = ret_info;
> > > > > > > +	  return true;
> > > > > > > +	}
> > > > > > > +      /* __sync_* builtins and some OpenMP builtins act as threading
> > > > > > > +	 barriers.  */
> > > > > > > +#undef DEF_SYNC_BUILTIN
> > > > > > > +#define DEF_SYNC_BUILTIN(ENUM, NAME, TYPE, ATTRS) case ENUM:
> > > > > > > +#include "sync-builtins.def"
> > > > > > > +#undef DEF_SYNC_BUILTIN
> > > > > > > +      case BUILT_IN_GOMP_ATOMIC_START:
> > > > > > > +      case BUILT_IN_GOMP_ATOMIC_END:
> > > > > > > +      case BUILT_IN_GOMP_BARRIER:
> > > > > > > +      case BUILT_IN_GOMP_BARRIER_CANCEL:
> > > > > > > +      case BUILT_IN_GOMP_TASKWAIT:
> > > > > > > +      case BUILT_IN_GOMP_TASKGROUP_END:
> > > > > > > +      case BUILT_IN_GOMP_CRITICAL_START:
> > > > > > > +      case BUILT_IN_GOMP_CRITICAL_END:
> > > > > > > +      case BUILT_IN_GOMP_CRITICAL_NAME_START:
> > > > > > > +      case BUILT_IN_GOMP_CRITICAL_NAME_END:
> > > > > > > +      case BUILT_IN_GOMP_LOOP_END:
> > > > > > > +      case BUILT_IN_GOMP_LOOP_END_CANCEL:
> > > > > > > +      case BUILT_IN_GOMP_ORDERED_START:
> > > > > > > +      case BUILT_IN_GOMP_ORDERED_END:
> > > > > > > +      case BUILT_IN_GOMP_SECTIONS_END:
> > > > > > > +      case BUILT_IN_GOMP_SECTIONS_END_CANCEL:
> > > > > > > +      case BUILT_IN_GOMP_SINGLE_COPY_START:
> > > > > > > +      case BUILT_IN_GOMP_SINGLE_COPY_END:
> > > > > > > +	{
> > > > > > > +	  const static struct ao_function_info ret_info
> > > > > > > +	       = {
> > > > > > > +		    -1,				/* num_param_reads.  */
> > > > > > > +		    {},				/* Param read.  */
> > > > > > > +		    -1,				/* num_param_writes.  */
> > > > > > > +		    {},				/* Param written.  */
> > > > > > > +		    AO_FUNCTION_BARRIER,	/* flags.  */
> > > > > > > +		 };
> > > > > > > +	  *info = ret_info;
> > > > > > > +	  return true;
> > > > > > > +	}
> > > > > > > +
> > > > > > > +      default:
> > > > > > > +	return false;
> > > > > > > +    }
> > > > > > > +}
> > > > > > > +
> > > > > > >  /* If the call CALL may use the memory reference REF return true,
> > > > > > >     otherwise return false.  */
> > > > > > >  
> > > > > > > @@ -2574,219 +3075,37 @@ ref_maybe_used_by_call_p_1 (gcall *call, ao_ref *ref, bool tbaa_p)
> > > > > > >    /* 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.  */
> > > > > > > +  struct ao_function_info info;
> > > > > > >    if (callee != NULL_TREE
> > > > > > > -      && gimple_call_builtin_p (call, BUILT_IN_NORMAL))
> > > > > > > -    switch (DECL_FUNCTION_CODE (callee))
> > > > > > > -      {
> > > > > > > -	/* All the following functions read memory pointed to by
> > > > > > > -	   their second argument.  strcat/strncat additionally
> > > > > > > -	   reads memory pointed to by the first argument.  */
> > > > > > > -	case BUILT_IN_STRCAT:
> > > > > > > -	case BUILT_IN_STRNCAT:
> > > > > > > -	  {
> > > > > > > -	    ao_ref dref;
> > > > > > > -	    ao_ref_init_from_ptr_and_size (&dref,
> > > > > > > -					   gimple_call_arg (call, 0),
> > > > > > > -					   NULL_TREE);
> > > > > > > -	    if (refs_may_alias_p_1 (&dref, ref, false))
> > > > > > > -	      return true;
> > > > > > > -	  }
> > > > > > > -	  /* FALLTHRU */
> > > > > > > -	case BUILT_IN_STRCPY:
> > > > > > > -	case BUILT_IN_STRNCPY:
> > > > > > > -	case BUILT_IN_MEMCPY:
> > > > > > > -	case BUILT_IN_MEMMOVE:
> > > > > > > -	case BUILT_IN_MEMPCPY:
> > > > > > > -	case BUILT_IN_STPCPY:
> > > > > > > -	case BUILT_IN_STPNCPY:
> > > > > > > -	case BUILT_IN_TM_MEMCPY:
> > > > > > > -	case BUILT_IN_TM_MEMMOVE:
> > > > > > > -	  {
> > > > > > > -	    ao_ref dref;
> > > > > > > -	    tree size = NULL_TREE;
> > > > > > > -	    if (gimple_call_num_args (call) == 3)
> > > > > > > -	      size = gimple_call_arg (call, 2);
> > > > > > > -	    ao_ref_init_from_ptr_and_size (&dref,
> > > > > > > -					   gimple_call_arg (call, 1),
> > > > > > > -					   size);
> > > > > > > -	    return refs_may_alias_p_1 (&dref, ref, false);
> > > > > > > -	  }
> > > > > > > -	case BUILT_IN_STRCAT_CHK:
> > > > > > > -	case BUILT_IN_STRNCAT_CHK:
> > > > > > > -	  {
> > > > > > > -	    ao_ref dref;
> > > > > > > -	    ao_ref_init_from_ptr_and_size (&dref,
> > > > > > > -					   gimple_call_arg (call, 0),
> > > > > > > -					   NULL_TREE);
> > > > > > > -	    if (refs_may_alias_p_1 (&dref, ref, false))
> > > > > > > -	      return true;
> > > > > > > -	  }
> > > > > > > -	  /* FALLTHRU */
> > > > > > > -	case BUILT_IN_STRCPY_CHK:
> > > > > > > -	case BUILT_IN_STRNCPY_CHK:
> > > > > > > -	case BUILT_IN_MEMCPY_CHK:
> > > > > > > -	case BUILT_IN_MEMMOVE_CHK:
> > > > > > > -	case BUILT_IN_MEMPCPY_CHK:
> > > > > > > -	case BUILT_IN_STPCPY_CHK:
> > > > > > > -	case BUILT_IN_STPNCPY_CHK:
> > > > > > > -	  {
> > > > > > > -	    ao_ref dref;
> > > > > > > -	    tree size = NULL_TREE;
> > > > > > > -	    if (gimple_call_num_args (call) == 4)
> > > > > > > -	      size = gimple_call_arg (call, 2);
> > > > > > > -	    ao_ref_init_from_ptr_and_size (&dref,
> > > > > > > -					   gimple_call_arg (call, 1),
> > > > > > > -					   size);
> > > > > > > -	    return refs_may_alias_p_1 (&dref, ref, false);
> > > > > > > -	  }
> > > > > > > -	case BUILT_IN_BCOPY:
> > > > > > > -	  {
> > > > > > > -	    ao_ref dref;
> > > > > > > -	    tree size = gimple_call_arg (call, 2);
> > > > > > > -	    ao_ref_init_from_ptr_and_size (&dref,
> > > > > > > -					   gimple_call_arg (call, 0),
> > > > > > > -					   size);
> > > > > > > -	    return refs_may_alias_p_1 (&dref, ref, false);
> > > > > > > -	  }
> > > > > > > -
> > > > > > > -	/* The following functions read memory pointed to by their
> > > > > > > -	   first argument.  */
> > > > > > > -	CASE_BUILT_IN_TM_LOAD (1):
> > > > > > > -	CASE_BUILT_IN_TM_LOAD (2):
> > > > > > > -	CASE_BUILT_IN_TM_LOAD (4):
> > > > > > > -	CASE_BUILT_IN_TM_LOAD (8):
> > > > > > > -	CASE_BUILT_IN_TM_LOAD (FLOAT):
> > > > > > > -	CASE_BUILT_IN_TM_LOAD (DOUBLE):
> > > > > > > -	CASE_BUILT_IN_TM_LOAD (LDOUBLE):
> > > > > > > -	CASE_BUILT_IN_TM_LOAD (M64):
> > > > > > > -	CASE_BUILT_IN_TM_LOAD (M128):
> > > > > > > -	CASE_BUILT_IN_TM_LOAD (M256):
> > > > > > > -	case BUILT_IN_TM_LOG:
> > > > > > > -	case BUILT_IN_TM_LOG_1:
> > > > > > > -	case BUILT_IN_TM_LOG_2:
> > > > > > > -	case BUILT_IN_TM_LOG_4:
> > > > > > > -	case BUILT_IN_TM_LOG_8:
> > > > > > > -	case BUILT_IN_TM_LOG_FLOAT:
> > > > > > > -	case BUILT_IN_TM_LOG_DOUBLE:
> > > > > > > -	case BUILT_IN_TM_LOG_LDOUBLE:
> > > > > > > -	case BUILT_IN_TM_LOG_M64:
> > > > > > > -	case BUILT_IN_TM_LOG_M128:
> > > > > > > -	case BUILT_IN_TM_LOG_M256:
> > > > > > > -	  return ptr_deref_may_alias_ref_p_1 (gimple_call_arg (call, 0), ref);
> > > > > > > -
> > > > > > > -	/* These read memory pointed to by the first argument.  */
> > > > > > > -	case BUILT_IN_STRDUP:
> > > > > > > -	case BUILT_IN_STRNDUP:
> > > > > > > -	case BUILT_IN_REALLOC:
> > > > > > > -	  {
> > > > > > > -	    ao_ref dref;
> > > > > > > -	    tree size = NULL_TREE;
> > > > > > > -	    if (gimple_call_num_args (call) == 2)
> > > > > > > -	      size = gimple_call_arg (call, 1);
> > > > > > > -	    ao_ref_init_from_ptr_and_size (&dref,
> > > > > > > -					   gimple_call_arg (call, 0),
> > > > > > > -					   size);
> > > > > > > -	    return refs_may_alias_p_1 (&dref, ref, false);
> > > > > > > -	  }
> > > > > > > -	/* These read memory pointed to by the first argument.  */
> > > > > > > -	case BUILT_IN_INDEX:
> > > > > > > -	case BUILT_IN_STRCHR:
> > > > > > > -	case BUILT_IN_STRRCHR:
> > > > > > > -	  {
> > > > > > > -	    ao_ref dref;
> > > > > > > -	    ao_ref_init_from_ptr_and_size (&dref,
> > > > > > > -					   gimple_call_arg (call, 0),
> > > > > > > -					   NULL_TREE);
> > > > > > > -	    return refs_may_alias_p_1 (&dref, ref, false);
> > > > > > > -	  }
> > > > > > > -	/* These read memory pointed to by the first argument with size
> > > > > > > -	   in the third argument.  */
> > > > > > > -	case BUILT_IN_MEMCHR:
> > > > > > > -	  {
> > > > > > > -	    ao_ref dref;
> > > > > > > -	    ao_ref_init_from_ptr_and_size (&dref,
> > > > > > > -					   gimple_call_arg (call, 0),
> > > > > > > -					   gimple_call_arg (call, 2));
> > > > > > > -	    return refs_may_alias_p_1 (&dref, ref, false);
> > > > > > > -	  }
> > > > > > > -	/* These read memory pointed to by the first and second arguments.  */
> > > > > > > -	case BUILT_IN_STRSTR:
> > > > > > > -	case BUILT_IN_STRPBRK:
> > > > > > > -	  {
> > > > > > > -	    ao_ref dref;
> > > > > > > -	    ao_ref_init_from_ptr_and_size (&dref,
> > > > > > > -					   gimple_call_arg (call, 0),
> > > > > > > -					   NULL_TREE);
> > > > > > > -	    if (refs_may_alias_p_1 (&dref, ref, false))
> > > > > > > -	      return true;
> > > > > > > -	    ao_ref_init_from_ptr_and_size (&dref,
> > > > > > > -					   gimple_call_arg (call, 1),
> > > > > > > -					   NULL_TREE);
> > > > > > > -	    return refs_may_alias_p_1 (&dref, ref, false);
> > > > > > > -	  }
> > > > > > > -
> > > > > > > -	/* The following builtins do not read from memory.  */
> > > > > > > -	case BUILT_IN_FREE:
> > > > > > > -	case BUILT_IN_MALLOC:
> > > > > > > -	case BUILT_IN_POSIX_MEMALIGN:
> > > > > > > -	case BUILT_IN_ALIGNED_ALLOC:
> > > > > > > -	case BUILT_IN_CALLOC:
> > > > > > > -	CASE_BUILT_IN_ALLOCA:
> > > > > > > -	case BUILT_IN_STACK_SAVE:
> > > > > > > -	case BUILT_IN_STACK_RESTORE:
> > > > > > > -	case BUILT_IN_MEMSET:
> > > > > > > -	case BUILT_IN_TM_MEMSET:
> > > > > > > -	case BUILT_IN_MEMSET_CHK:
> > > > > > > -	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_SINCOS:
> > > > > > > -	case BUILT_IN_SINCOSF:
> > > > > > > -	case BUILT_IN_SINCOSL:
> > > > > > > -	case BUILT_IN_ASSUME_ALIGNED:
> > > > > > > -	case BUILT_IN_VA_END:
> > > > > > > +      && gimple_call_builtin_p (call, BUILT_IN_NORMAL)
> > > > > > > +      && (ao_classify_builtin (callee, &info)))
> > > > > > > +    {
> > > > > > > +      if (info.flags & AO_FUNCTION_BARRIER)
> > > > > > > +	return true;
> > > > > > > +      if (info.num_param_reads >= 0)
> > > > > > > +	{
> > > > > > > +	  for (int i = 0; i < info.num_param_reads; i++)
> > > > > > > +	    {
> > > > > > > +	      ao_ref dref;
> > > > > > > +	      tree size = NULL_TREE;
> > > > > > > +
> > > > > > > +	      gcc_checking_assert (info.reads[i].size_param
> > > > > > > +				   != info.reads[i].param);
> > > > > > > +	      if (info.reads[i].size_param != -1)
> > > > > > > +		size = gimple_call_arg (call, info.reads[i].size);
> > > > > > > +	      else if (info.reads[i].size)
> > > > > > > +		size = build_int_cst (size_type_node, info.reads[i].size);
> > > > > > > +	      ao_ref_init_from_ptr_and_size (&dref,
> > > > > > > +					     gimple_call_arg
> > > > > > > +						 (call,
> > > > > > > +						  info.reads[i].param),
> > > > > > > +					     size);
> > > > > > > +	      if (refs_may_alias_p_1 (&dref, ref, tbaa_p))
> > > > > > > +		return true;
> > > > > > > +	    }
> > > > > > >  	  return false;
> > > > > > > -	/* __sync_* builtins and some OpenMP builtins act as threading
> > > > > > > -	   barriers.  */
> > > > > > > -#undef DEF_SYNC_BUILTIN
> > > > > > > -#define DEF_SYNC_BUILTIN(ENUM, NAME, TYPE, ATTRS) case ENUM:
> > > > > > > -#include "sync-builtins.def"
> > > > > > > -#undef DEF_SYNC_BUILTIN
> > > > > > > -	case BUILT_IN_GOMP_ATOMIC_START:
> > > > > > > -	case BUILT_IN_GOMP_ATOMIC_END:
> > > > > > > -	case BUILT_IN_GOMP_BARRIER:
> > > > > > > -	case BUILT_IN_GOMP_BARRIER_CANCEL:
> > > > > > > -	case BUILT_IN_GOMP_TASKWAIT:
> > > > > > > -	case BUILT_IN_GOMP_TASKGROUP_END:
> > > > > > > -	case BUILT_IN_GOMP_CRITICAL_START:
> > > > > > > -	case BUILT_IN_GOMP_CRITICAL_END:
> > > > > > > -	case BUILT_IN_GOMP_CRITICAL_NAME_START:
> > > > > > > -	case BUILT_IN_GOMP_CRITICAL_NAME_END:
> > > > > > > -	case BUILT_IN_GOMP_LOOP_END:
> > > > > > > -	case BUILT_IN_GOMP_LOOP_END_CANCEL:
> > > > > > > -	case BUILT_IN_GOMP_ORDERED_START:
> > > > > > > -	case BUILT_IN_GOMP_ORDERED_END:
> > > > > > > -	case BUILT_IN_GOMP_SECTIONS_END:
> > > > > > > -	case BUILT_IN_GOMP_SECTIONS_END_CANCEL:
> > > > > > > -	case BUILT_IN_GOMP_SINGLE_COPY_START:
> > > > > > > -	case BUILT_IN_GOMP_SINGLE_COPY_END:
> > > > > > > -	  return true;
> > > > > > > -
> > > > > > > -	default:
> > > > > > > -	  /* Fallthru to general call handling.  */;
> > > > > > > -      }
> > > > > > > +	}
> > > > > > > +    }
> > > > > > >  
> > > > > > >    /* Check if base is a global static variable that is not read
> > > > > > >       by the function.  */
> > > > > > > @@ -2961,7 +3280,9 @@ call_may_clobber_ref_p_1 (gcall *call, ao_ref *ref, bool tbaa_p)
> > > > > > >  	  modref_summary *summary = get_modref_function_summary (node);
> > > > > > >  	  if (summary)
> > > > > > >  	    {
> > > > > > > -	      if (!modref_may_conflict (call, summary->stores, ref, tbaa_p))
> > > > > > > +	      if (!modref_may_conflict (call, summary->stores, ref, tbaa_p)
> > > > > > > +		  && (!summary->writes_errno
> > > > > > > +		      || !targetm.ref_may_alias_errno (ref)))
> > > > > > >  		{
> > > > > > >  		  alias_stats.modref_clobber_no_alias++;
> > > > > > >  		  if (dump_file && (dump_flags & TDF_DETAILS))
> > > > > > > @@ -3016,205 +3337,43 @@ call_may_clobber_ref_p_1 (gcall *call, ao_ref *ref, bool tbaa_p)
> > > > > > >        && SSA_NAME_POINTS_TO_READONLY_MEMORY (TREE_OPERAND (base, 0)))
> > > > > > >      return false;
> > > > > > >  
> > > > > > > +  struct ao_function_info info;
> > > > > > >    /* 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.  */
> > > > > > > +     escape points.  */
> > > > > > >    if (callee != NULL_TREE
> > > > > > > -      && gimple_call_builtin_p (call, 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_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:
> > > > > > > -	case BUILT_IN_MEMSET:
> > > > > > > -	case BUILT_IN_TM_MEMSET:
> > > > > > > -	CASE_BUILT_IN_TM_STORE (1):
> > > > > > > -	CASE_BUILT_IN_TM_STORE (2):
> > > > > > > -	CASE_BUILT_IN_TM_STORE (4):
> > > > > > > -	CASE_BUILT_IN_TM_STORE (8):
> > > > > > > -	CASE_BUILT_IN_TM_STORE (FLOAT):
> > > > > > > -	CASE_BUILT_IN_TM_STORE (DOUBLE):
> > > > > > > -	CASE_BUILT_IN_TM_STORE (LDOUBLE):
> > > > > > > -	CASE_BUILT_IN_TM_STORE (M64):
> > > > > > > -	CASE_BUILT_IN_TM_STORE (M128):
> > > > > > > -	CASE_BUILT_IN_TM_STORE (M256):
> > > > > > > -	case BUILT_IN_TM_MEMCPY:
> > > > > > > -	case BUILT_IN_TM_MEMMOVE:
> > > > > > > -	  {
> > > > > > > -	    ao_ref dref;
> > > > > > > -	    tree size = NULL_TREE;
> > > > > > > -	    /* Don't pass in size for strncat, as the maximum size
> > > > > > > -	       is strlen (dest) + n + 1 instead of n, resp.
> > > > > > > -	       n + 1 at dest + strlen (dest), but strlen (dest) isn't
> > > > > > > -	       known.  */
> > > > > > > -	    if (gimple_call_num_args (call) == 3
> > > > > > > -		&& DECL_FUNCTION_CODE (callee) != BUILT_IN_STRNCAT)
> > > > > > > -	      size = gimple_call_arg (call, 2);
> > > > > > > -	    ao_ref_init_from_ptr_and_size (&dref,
> > > > > > > -					   gimple_call_arg (call, 0),
> > > > > > > -					   size);
> > > > > > > -	    return refs_may_alias_p_1 (&dref, ref, false);
> > > > > > > -	  }
> > > > > > > -	case BUILT_IN_STRCPY_CHK:
> > > > > > > -	case BUILT_IN_STRNCPY_CHK:
> > > > > > > -	case BUILT_IN_MEMCPY_CHK:
> > > > > > > -	case BUILT_IN_MEMMOVE_CHK:
> > > > > > > -	case BUILT_IN_MEMPCPY_CHK:
> > > > > > > -	case BUILT_IN_STPCPY_CHK:
> > > > > > > -	case BUILT_IN_STPNCPY_CHK:
> > > > > > > -	case BUILT_IN_STRCAT_CHK:
> > > > > > > -	case BUILT_IN_STRNCAT_CHK:
> > > > > > > -	case BUILT_IN_MEMSET_CHK:
> > > > > > > -	  {
> > > > > > > -	    ao_ref dref;
> > > > > > > -	    tree size = NULL_TREE;
> > > > > > > -	    /* Don't pass in size for __strncat_chk, as the maximum size
> > > > > > > -	       is strlen (dest) + n + 1 instead of n, resp.
> > > > > > > -	       n + 1 at dest + strlen (dest), but strlen (dest) isn't
> > > > > > > -	       known.  */
> > > > > > > -	    if (gimple_call_num_args (call) == 4
> > > > > > > -		&& DECL_FUNCTION_CODE (callee) != BUILT_IN_STRNCAT_CHK)
> > > > > > > -	      size = gimple_call_arg (call, 2);
> > > > > > > -	    ao_ref_init_from_ptr_and_size (&dref,
> > > > > > > -					   gimple_call_arg (call, 0),
> > > > > > > -					   size);
> > > > > > > -	    return refs_may_alias_p_1 (&dref, ref, false);
> > > > > > > -	  }
> > > > > > > -	case BUILT_IN_BCOPY:
> > > > > > > -	  {
> > > > > > > -	    ao_ref dref;
> > > > > > > -	    tree size = gimple_call_arg (call, 2);
> > > > > > > -	    ao_ref_init_from_ptr_and_size (&dref,
> > > > > > > -					   gimple_call_arg (call, 1),
> > > > > > > -					   size);
> > > > > > > -	    return refs_may_alias_p_1 (&dref, ref, false);
> > > > > > > -	  }
> > > > > > > -	/* Allocating memory does not have any side-effects apart from
> > > > > > > -	   being the definition point for the pointer.  */
> > > > > > > -	case BUILT_IN_MALLOC:
> > > > > > > -	case BUILT_IN_ALIGNED_ALLOC:
> > > > > > > -	case BUILT_IN_CALLOC:
> > > > > > > -	case BUILT_IN_STRDUP:
> > > > > > > -	case BUILT_IN_STRNDUP:
> > > > > > > -	  /* Unix98 specifies that errno is set on allocation failure.  */
> > > > > > > -	  if (flag_errno_math
> > > > > > > -	      && targetm.ref_may_alias_errno (ref))
> > > > > > > -	    return true;
> > > > > > > -	  return false;
> > > > > > > -	case BUILT_IN_STACK_SAVE:
> > > > > > > -	CASE_BUILT_IN_ALLOCA:
> > > > > > > -	case BUILT_IN_ASSUME_ALIGNED:
> > > > > > > +      && gimple_call_builtin_p (call, BUILT_IN_NORMAL)
> > > > > > > +      && (ao_classify_builtin (callee, &info)))
> > > > > > > +    {
> > > > > > > +      if (info.flags & AO_FUNCTION_BARRIER)
> > > > > > > +	return true;
> > > > > > > +      if ((info.flags & AO_FUNCTION_ERRNO)
> > > > > > > +	  && flag_errno_math
> > > > > > > +	  && targetm.ref_may_alias_errno (ref))
> > > > > > > +	return true;
> > > > > > > +      if (info.num_param_writes >= 0)
> > > > > > > +	{
> > > > > > > +	  for (int i = 0; i < info.num_param_writes; i++)
> > > > > > > +	    {
> > > > > > > +	      ao_ref dref;
> > > > > > > +	      tree size = NULL_TREE;
> > > > > > > +
> > > > > > > +	      gcc_checking_assert (info.writes[i].size_param
> > > > > > > +				   != info.writes[i].param);
> > > > > > > +	      if (info.writes[i].size_param != -1)
> > > > > > > +		size = gimple_call_arg (call, info.writes[i].size_param);
> > > > > > > +	      else if (info.writes[i].size)
> > > > > > > +		size = build_int_cst (size_type_node, info.writes[i].size);
> > > > > > > +	      ao_ref_init_from_ptr_and_size (&dref,
> > > > > > > +					     gimple_call_arg
> > > > > > > +						 (call,
> > > > > > > +						  info.writes[i].param),
> > > > > > > +					     size);
> > > > > > > +	      if (refs_may_alias_p_1 (&dref, ref, tbaa_p))
> > > > > > > +		return true;
> > > > > > > +	    }
> > > > > > >  	  return false;
> > > > > > > -	/* But posix_memalign stores a pointer into the memory pointed to
> > > > > > > -	   by its first argument.  */
> > > > > > > -	case BUILT_IN_POSIX_MEMALIGN:
> > > > > > > -	  {
> > > > > > > -	    tree ptrptr = gimple_call_arg (call, 0);
> > > > > > > -	    ao_ref dref;
> > > > > > > -	    ao_ref_init_from_ptr_and_size (&dref, ptrptr,
> > > > > > > -					   TYPE_SIZE_UNIT (ptr_type_node));
> > > > > > > -	    return (refs_may_alias_p_1 (&dref, ref, false)
> > > > > > > -		    || (flag_errno_math
> > > > > > > -			&& targetm.ref_may_alias_errno (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.  */
> > > > > > > -	case BUILT_IN_FREE:
> > > > > > > -	case BUILT_IN_VA_END:
> > > > > > > -	  {
> > > > > > > -	    tree ptr = gimple_call_arg (call, 0);
> > > > > > > -	    return ptr_deref_may_alias_ref_p_1 (ptr, ref);
> > > > > > > -	  }
> > > > > > > -	/* Realloc serves both as allocation point and deallocation point.  */
> > > > > > > -	case BUILT_IN_REALLOC:
> > > > > > > -	  {
> > > > > > > -	    tree ptr = gimple_call_arg (call, 0);
> > > > > > > -	    /* Unix98 specifies that errno is set on allocation failure.  */
> > > > > > > -	    return ((flag_errno_math
> > > > > > > -		     && targetm.ref_may_alias_errno (ref))
> > > > > > > -		    || ptr_deref_may_alias_ref_p_1 (ptr, ref));
> > > > > > > -	  }
> > > > > > > -	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:
> > > > > > > -	  {
> > > > > > > -	    tree out = gimple_call_arg (call, 1);
> > > > > > > -	    if (ptr_deref_may_alias_ref_p_1 (out, ref))
> > > > > > > -	      return true;
> > > > > > > -	    if (flag_errno_math)
> > > > > > > -	      break;
> > > > > > > -	    return false;
> > > > > > > -	  }
> > > > > > > -	case BUILT_IN_FREXP:
> > > > > > > -	case BUILT_IN_FREXPF:
> > > > > > > -	case BUILT_IN_FREXPL:
> > > > > > > -	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_1 (out, ref);
> > > > > > > -	  }
> > > > > > > -	case BUILT_IN_REMQUO:
> > > > > > > -	case BUILT_IN_REMQUOF:
> > > > > > > -	case BUILT_IN_REMQUOL:
> > > > > > > -	  {
> > > > > > > -	    tree out = gimple_call_arg (call, 2);
> > > > > > > -	    if (ptr_deref_may_alias_ref_p_1 (out, ref))
> > > > > > > -	      return true;
> > > > > > > -	    if (flag_errno_math)
> > > > > > > -	      break;
> > > > > > > -	    return false;
> > > > > > > -	  }
> > > > > > > -	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);
> > > > > > > -	    return (ptr_deref_may_alias_ref_p_1 (sin, ref)
> > > > > > > -		    || ptr_deref_may_alias_ref_p_1 (cos, ref));
> > > > > > > -	  }
> > > > > > > -	/* __sync_* builtins and some OpenMP builtins act as threading
> > > > > > > -	   barriers.  */
> > > > > > > -#undef DEF_SYNC_BUILTIN
> > > > > > > -#define DEF_SYNC_BUILTIN(ENUM, NAME, TYPE, ATTRS) case ENUM:
> > > > > > > -#include "sync-builtins.def"
> > > > > > > -#undef DEF_SYNC_BUILTIN
> > > > > > > -	case BUILT_IN_GOMP_ATOMIC_START:
> > > > > > > -	case BUILT_IN_GOMP_ATOMIC_END:
> > > > > > > -	case BUILT_IN_GOMP_BARRIER:
> > > > > > > -	case BUILT_IN_GOMP_BARRIER_CANCEL:
> > > > > > > -	case BUILT_IN_GOMP_TASKWAIT:
> > > > > > > -	case BUILT_IN_GOMP_TASKGROUP_END:
> > > > > > > -	case BUILT_IN_GOMP_CRITICAL_START:
> > > > > > > -	case BUILT_IN_GOMP_CRITICAL_END:
> > > > > > > -	case BUILT_IN_GOMP_CRITICAL_NAME_START:
> > > > > > > -	case BUILT_IN_GOMP_CRITICAL_NAME_END:
> > > > > > > -	case BUILT_IN_GOMP_LOOP_END:
> > > > > > > -	case BUILT_IN_GOMP_LOOP_END_CANCEL:
> > > > > > > -	case BUILT_IN_GOMP_ORDERED_START:
> > > > > > > -	case BUILT_IN_GOMP_ORDERED_END:
> > > > > > > -	case BUILT_IN_GOMP_SECTIONS_END:
> > > > > > > -	case BUILT_IN_GOMP_SECTIONS_END_CANCEL:
> > > > > > > -	case BUILT_IN_GOMP_SINGLE_COPY_START:
> > > > > > > -	case BUILT_IN_GOMP_SINGLE_COPY_END:
> > > > > > > -	  return true;
> > > > > > > -	default:
> > > > > > > -	  /* Fallthru to general call handling.  */;
> > > > > > > -      }
> > > > > > > +	}
> > > > > > > +    }
> > > > > > >  
> > > > > > >    /* Check if base is a global static variable that is not written
> > > > > > >       by the function.  */
> > > > > > > 
> > > > > > 
> > > > > > -- 
> > > > > > Richard Biener <rguenther@suse.de>
> > > > > > SUSE Software Solutions Germany GmbH, Maxfeldstrasse 5, 90409 Nuernberg,
> > > > > > Germany; GF: Felix Imend
> > > > > 
> > > > > 
> > > > 
> > > > -- 
> > > > Richard Biener <rguenther@suse.de>
> > > > SUSE Software Solutions Germany GmbH, Maxfeldstrasse 5, 90409 Nuernberg,
> > > > Germany; GF: Felix Imend
> > > 
> > > 
> > 
> > -- 
> > Richard Biener <rguenther@suse.de>
> > SUSE Software Solutions Germany GmbH, Maxfeldstrasse 5, 90409 Nuernberg,
> > Germany; GF: Felix Imend
>
diff mbox series

Patch

diff --git a/gcc/tree-ssa-alias.h b/gcc/tree-ssa-alias.h
index 1dd02c0ea62..eecb8da6dd7 100644
--- a/gcc/tree-ssa-alias.h
+++ b/gcc/tree-ssa-alias.h
@@ -108,6 +108,33 @@  ao_ref::max_size_known_p () const
   return known_size_p (max_size);
 }
 
+/* Flags used in ao_function_info.  */
+
+enum ao_function_flags
+{
+  AO_FUNCTION_BARRIER = 1,
+  AO_FUNCTION_ERRNO = 2,
+};
+
+/* Describe side effects relevant for alias analysis of function call to
+   DECL.  */
+
+struct ao_function_info
+{
+  int num_param_reads;  /* Number of parameters function reads from,
+			   -1 if reads are unknown.  */
+  struct ao_access_info
+    {
+      char param; 	/* Index of parameter read/written from.  */
+      char size_param;	/* Index of parameter specifying size of the access,
+			   -1 if unknown.  */
+      char size;	/* Size of access if known, 0 if unknown.  */
+    } reads[2];
+  int num_param_writes;
+  struct ao_access_info writes[2];
+  enum ao_function_flags flags;
+};
+
 /* In tree-ssa-alias.c  */
 extern void ao_ref_init (ao_ref *, tree);
 extern void ao_ref_init_from_ptr_and_size (ao_ref *, tree, tree);
@@ -158,6 +185,7 @@  extern void debug (pt_solution *ptr);
 extern void dump_points_to_info_for (FILE *, tree);
 extern void debug_points_to_info_for (tree);
 extern void dump_alias_stats (FILE *);
+extern bool ao_classify_builtin (tree callee, ao_function_info *info);
 
 
 /* In tree-ssa-structalias.c  */
diff --git a/gcc/tree-ssa-alias.c b/gcc/tree-ssa-alias.c
index fe390d4ffbe..c182e7bb39c 100644
--- a/gcc/tree-ssa-alias.c
+++ b/gcc/tree-ssa-alias.c
@@ -2503,6 +2503,507 @@  modref_may_conflict (const gimple *stmt,
   return false;
 }
 
+/* If CALLEE has known side effects, fill in INFO and return true.
+   See tree-ssa-structalias.c:find_func_aliases
+   for the list of builtins we might need to handle here.  */
+
+bool
+ao_classify_builtin (tree callee, ao_function_info *info)
+{
+  built_in_function code = DECL_FUNCTION_CODE (callee);
+
+  switch (code)
+    {
+      /* All the following functions read memory pointed to by
+	 their second argument and write memory pointed to by first
+	 argument.
+	 strcat/strncat additionally reads memory pointed to by the first
+	 argument.  */
+      case BUILT_IN_STRCAT:
+	{
+	  const static struct ao_function_info ret_info
+	       = {
+		    2,				/* num_param_reads.  */
+
+		    /* Reads and write descriptors are triples containing:
+		       - index of parameter read
+		       - index of parameter specifying access size
+			 (-1 if unknown)
+		       - access size in bytes (0 if unkown).  */
+
+		    {{0, -1, 0}, {1, -1, 0}},	/* Param read.  */
+		    1,				/* num_param_writes.  */
+		    {{0, -1, 0}},		/* Param written.  */
+		    (ao_function_flags)0,	/* flags.  */
+		 };
+	  *info = ret_info;
+	  return true;
+	}
+      case BUILT_IN_STRNCAT:
+	{
+	  const static struct ao_function_info ret_info
+	       = {
+		    2,				/* num_param_reads.  */
+		    {{0, -1, 0}, {1, 2, 0}},	/* Param read.  */
+		    1,				/* num_param_writes.  */
+		    {{0, -1, 0}},		/* Param written.  */
+		    (ao_function_flags)0,	/* flags.  */
+		 };
+	  *info = ret_info;
+	  return true;
+	}
+      case BUILT_IN_STRCPY:
+      case BUILT_IN_STPCPY:
+	{
+	  const static struct ao_function_info ret_info
+	       = {
+		    1,				/* num_param_reads.  */
+		    {{1, -1, 0}},		/* Param read.  */
+		    1,				/* num_param_writes.  */
+		    {{0, -1, 0}},		/* Param written.  */
+		    (ao_function_flags)0,	/* flags.  */
+		 };
+	  *info = ret_info;
+	  return true;
+	}
+      case BUILT_IN_STRNCPY:
+      case BUILT_IN_MEMCPY:
+      case BUILT_IN_MEMMOVE:
+      case BUILT_IN_MEMPCPY:
+      case BUILT_IN_STPNCPY:
+      case BUILT_IN_TM_MEMCPY:
+      case BUILT_IN_TM_MEMMOVE:
+	{
+	  const static struct ao_function_info ret_info
+	       = {
+		    1,				/* num_param_reads.  */
+		    {{1, 2, 0}},		/* Param read.  */
+		    1,				/* num_param_writes.  */
+		    {{0, 2, 0}},		/* Param written.  */
+		    (ao_function_flags)0,	/* flags.  */
+		 };
+	  *info = ret_info;
+	  return true;
+	}
+      case BUILT_IN_STRCAT_CHK:
+	{
+	  const static struct ao_function_info ret_info
+	       = {
+		    2,				/* num_param_reads.  */
+		    {{0, -1, 0}, {1, -1, 0}},	/* Param read.  */
+		    1,				/* num_param_writes.  */
+		    {{0, -1, 0}},		/* Param written.  */
+		    (ao_function_flags)0,	/* flags.  */
+		 };
+	  *info = ret_info;
+	  return true;
+	}
+      case BUILT_IN_STRNCAT_CHK:
+	{
+	  const static struct ao_function_info ret_info
+	       = {
+		    2,				/* num_param_reads.  */
+		    {{0, -1, 0}, {1, 2, 0}},	/* Param read.  */
+		    1,				/* num_param_writes.  */
+		    {{0, -1, 0}},		/* Param written.  */
+		    (ao_function_flags)0,	/* flags.  */
+		 };
+	  *info = ret_info;
+	  return true;
+	}
+      case BUILT_IN_STRCPY_CHK:
+      case BUILT_IN_STPCPY_CHK:
+	{
+	  const static struct ao_function_info ret_info
+	       = {
+		    1,				/* num_param_reads.  */
+		    {{1, -1, 0}},		/* Param read.  */
+		    1,				/* num_param_writes.  */
+		    {{0, -1, 0}},		/* Param written.  */
+		    (ao_function_flags)0,	/* flags.  */
+		 };
+	  *info = ret_info;
+	  return true;
+	}
+      case BUILT_IN_STRNCPY_CHK:
+      case BUILT_IN_MEMCPY_CHK:
+      case BUILT_IN_MEMMOVE_CHK:
+      case BUILT_IN_MEMPCPY_CHK:
+      case BUILT_IN_STPNCPY_CHK:
+	{
+	  const static struct ao_function_info ret_info
+	       = {
+		    1,				/* num_param_reads.  */
+		    {{1, 2, 0}},		/* Param read.  */
+		    1,				/* num_param_writes.  */
+		    {{0, 2, 0}},		/* Param written.  */
+		    (ao_function_flags)0,	/* flags.  */
+		 };
+	  *info = ret_info;
+	  return true;
+	}
+      case BUILT_IN_BCOPY:
+	{
+	  const static struct ao_function_info ret_info
+	       = {
+		    1,				/* num_param_reads.  */
+		    {{0, 2, 0}},		/* Param read.  */
+		    1,				/* num_param_writes.  */
+		    {{1, 2, 0}},		/* Param written.  */
+		    (ao_function_flags)0,	/* flags.  */
+		 };
+	  *info = ret_info;
+	  return true;
+	}
+
+      /* The following functions read memory pointed to by their
+	 first argument.  */
+      CASE_BUILT_IN_TM_LOAD (1):
+      CASE_BUILT_IN_TM_LOAD (2):
+      CASE_BUILT_IN_TM_LOAD (4):
+      CASE_BUILT_IN_TM_LOAD (8):
+      CASE_BUILT_IN_TM_LOAD (FLOAT):
+      CASE_BUILT_IN_TM_LOAD (DOUBLE):
+      CASE_BUILT_IN_TM_LOAD (LDOUBLE):
+      CASE_BUILT_IN_TM_LOAD (M64):
+      CASE_BUILT_IN_TM_LOAD (M128):
+      CASE_BUILT_IN_TM_LOAD (M256):
+      case BUILT_IN_TM_LOG:
+      case BUILT_IN_TM_LOG_1:
+      case BUILT_IN_TM_LOG_2:
+      case BUILT_IN_TM_LOG_4:
+      case BUILT_IN_TM_LOG_8:
+      case BUILT_IN_TM_LOG_FLOAT:
+      case BUILT_IN_TM_LOG_DOUBLE:
+      case BUILT_IN_TM_LOG_LDOUBLE:
+      case BUILT_IN_TM_LOG_M64:
+      case BUILT_IN_TM_LOG_M128:
+      case BUILT_IN_TM_LOG_M256:
+
+      case BUILT_IN_INDEX:
+      case BUILT_IN_STRCHR:
+      case BUILT_IN_STRRCHR:
+	{
+	  const static struct ao_function_info ret_info
+	       = {
+		    1,				/* num_param_reads.  */
+		    /* TODO: For TM builtins size is known.  */
+		    {{0, -1, 0}},		/* Param read.  */
+		    0,				/* num_param_writes.  */
+		    {},				/* Param written.  */
+		    (ao_function_flags)0,	/* flags.  */
+		 };
+	  *info = ret_info;
+	  return true;
+	}
+
+      /* These read memory pointed to by the first argument.
+	 Allocating memory does not have any side-effects apart from
+	 being the definition point for the pointer.
+	 Unix98 specifies that errno is set on allocation failure.  */
+      case BUILT_IN_STRDUP:
+	{
+	  const static struct ao_function_info ret_info
+	       = {
+		    1,				/* num_param_reads.  */
+		    {{0, -1, 0}},		/* Param read.  */
+		    0,				/* num_param_writes.  */
+		    {},				/* Param written.  */
+		    AO_FUNCTION_ERRNO,		/* flags.  */
+		 };
+	  *info = ret_info;
+	  return true;
+	}
+      case BUILT_IN_STRNDUP:
+	{
+	  const static struct ao_function_info ret_info
+	       = {
+		    1,				/* num_param_reads.  */
+		    {{0, 1, 0}},		/* Param read.  */
+		    0,				/* num_param_writes.  */
+		    {},				/* Param written.  */
+		    AO_FUNCTION_ERRNO,		/* flags.  */
+		 };
+	  *info = ret_info;
+	  return true;
+	}
+      /* Allocating memory does not have any side-effects apart from
+	 being the definition point for the pointer.  */
+      case BUILT_IN_MALLOC:
+      case BUILT_IN_ALIGNED_ALLOC:
+      case BUILT_IN_CALLOC:
+	{
+	  const static struct ao_function_info ret_info
+	       = {
+		    0,				/* num_param_reads.  */
+		    {},				/* Param read.  */
+		    0,				/* num_param_writes.  */
+		    {},				/* Param written.  */
+		    AO_FUNCTION_ERRNO,		/* flags.  */
+		 };
+	  *info = ret_info;
+	  return true;
+	}
+      /* These read memory pointed to by the first argument with size
+	 in the third argument.  */
+      case BUILT_IN_MEMCHR:
+	{
+	  const static struct ao_function_info ret_info
+	       = {
+		    1,				/* num_param_reads.  */
+		    {{0, 2, 0}},		/* Param read.  */
+		    0,				/* num_param_writes.  */
+		    {},				/* Param written.  */
+		    (ao_function_flags)0,	/* flags.  */
+		 };
+	  *info = ret_info;
+	  return true;
+	}
+      /* These read memory pointed to by the first and second arguments.  */
+      case BUILT_IN_STRSTR:
+      case BUILT_IN_STRPBRK:
+	{
+	  static struct ao_function_info ret_info
+	       = {
+		    2,				/* num_param_reads.  */
+		    {{0, -1, 0}, {1, -1, 0}},	/* Param read.  */
+		    0,				/* num_param_writes.  */
+		    {},				/* Param written.  */
+		    (ao_function_flags)0,	/* flags.  */
+		 };
+	  *info = ret_info;
+	  return true;
+	}
+      /* Freeing memory kills the pointed-to memory.  More importantly
+	 the call has to serve as a barrier for moving loads and stores
+	 across it.  */
+      case BUILT_IN_FREE:
+      case BUILT_IN_VA_END:
+	{
+	  const static struct ao_function_info ret_info
+	       = {
+		    0,				/* num_param_reads.  */
+		    {},				/* Param read.  */
+		    1,				/* num_param_writes.  */
+		    {{0, -1, 0}},		/* Param written.  */
+		    (ao_function_flags)0,	/* flags.  */
+		 };
+	  *info = ret_info;
+	  return true;
+	}
+      /* Realloc serves both as allocation point and deallocation point.  */
+      case BUILT_IN_REALLOC:
+	{
+	  const static struct ao_function_info ret_info
+	       = {
+		    1,				/* num_param_reads.  */
+		    {{0, 1, 0}},		/* Param read.  */
+		    0,				/* num_param_writes.  */
+		    {{0, -1, 0}},		/* Param written.  */
+		    AO_FUNCTION_ERRNO,		/* flags.  */
+		 };
+	  *info = ret_info;
+	  return true;
+	}
+      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:
+	{
+	  const static struct ao_function_info ret_info
+	       = {
+		    0,				/* num_param_reads.  */
+		    {},				/* Param read.  */
+		    1,				/* num_param_writes.  */
+		    {{1, -1, 0}},		/* Param written.  */
+		    AO_FUNCTION_ERRNO,		/* flags.  */
+		 };
+	  *info = ret_info;
+	  return true;
+	}
+      case BUILT_IN_FREXP:
+      case BUILT_IN_FREXPF:
+      case BUILT_IN_FREXPL:
+      case BUILT_IN_MODF:
+      case BUILT_IN_MODFF:
+      case BUILT_IN_MODFL:
+	{
+	  const static struct ao_function_info ret_info
+	       = {
+		    0,				/* num_param_reads.  */
+		    {},				/* Param read.  */
+		    1,				/* num_param_writes.  */
+		    {{1, -1, 0}},		/* Param written.  */
+		    (ao_function_flags)0,	/* flags.  */
+		 };
+	  *info = ret_info;
+	  return true;
+	}
+      case BUILT_IN_REMQUO:
+      case BUILT_IN_REMQUOF:
+      case BUILT_IN_REMQUOL:
+	{
+	  const static struct ao_function_info ret_info
+	       = {
+		    0,				/* num_param_reads.  */
+		    {},				/* Param read.  */
+		    1,				/* num_param_writes.  */
+		    {{2, -1, 0}},		/* Param written.  */
+		    (ao_function_flags)0,	/* flags.  */
+		 };
+	  *info = ret_info;
+	  return true;
+	}
+      case BUILT_IN_SINCOS:
+      case BUILT_IN_SINCOSF:
+      case BUILT_IN_SINCOSL:
+	{
+	  static struct ao_function_info ret_info
+	       = {
+		    0,				/* num_param_reads.  */
+		    {},				/* Param read.  */
+		    1,				/* num_param_writes.  */
+		    {{1, -1, 0}, {2, -1, 0}},	/* Param written.  */
+		    (ao_function_flags)0,	/* flags.  */
+		 };
+	  tree type = float_ptr_type_node;
+	  if (code == BUILT_IN_SINCOS)
+	    type = double_ptr_type_node;
+	  else
+	    type = long_double_ptr_type_node;
+	  ret_info.writes[0].size = ret_info.writes[1].size
+		 = tree_to_uhwi (TYPE_SIZE_UNIT (type));
+	  *info = ret_info;
+	  return true;
+	}
+      case BUILT_IN_MEMSET:
+      case BUILT_IN_MEMSET_CHK:
+      case BUILT_IN_TM_MEMSET:
+	{
+	  const static struct ao_function_info ret_info
+	       = {
+		    0,				/* num_param_reads.  */
+		    {},				/* Param read.  */
+		    1,				/* num_param_writes.  */
+		    {0, 2, 0},			/* Param written.  */
+		    (ao_function_flags)0,	/* flags.  */
+		 };
+	  *info = ret_info;
+	  return true;
+	}
+      CASE_BUILT_IN_TM_STORE (1):
+      CASE_BUILT_IN_TM_STORE (2):
+      CASE_BUILT_IN_TM_STORE (4):
+      CASE_BUILT_IN_TM_STORE (8):
+      CASE_BUILT_IN_TM_STORE (FLOAT):
+      CASE_BUILT_IN_TM_STORE (DOUBLE):
+      CASE_BUILT_IN_TM_STORE (LDOUBLE):
+      CASE_BUILT_IN_TM_STORE (M64):
+      CASE_BUILT_IN_TM_STORE (M128):
+      CASE_BUILT_IN_TM_STORE (M256):
+	{
+	  const static struct ao_function_info ret_info
+	       = {
+		    0,				/* num_param_reads.  */
+		    {},				/* Param read.  */
+		    1,				/* num_param_writes.  */
+		    /* TODO: Size is known.  */
+		    {0, -1, 0},			/* Param written.  */
+		    (ao_function_flags)0,	/* flags.  */
+		 };
+	  *info = ret_info;
+	  return true;
+	}
+      case BUILT_IN_STACK_SAVE:
+      CASE_BUILT_IN_ALLOCA:
+      case BUILT_IN_ASSUME_ALIGNED:
+	{
+	  const static struct ao_function_info ret_info
+	       = {
+		    0,				/* num_param_reads.  */
+		    {},				/* Param read.  */
+		    0,				/* num_param_writes.  */
+		    {},				/* Param written.  */
+		    (ao_function_flags)0,	/* flags.  */
+		 };
+	  *info = ret_info;
+	  return true;
+	}
+      /* But posix_memalign stores a pointer into the memory pointed to
+	 by its first argument.  */
+      case BUILT_IN_POSIX_MEMALIGN:
+	{
+	  static struct ao_function_info ret_info
+	       = {
+		    0,				/* num_param_reads.  */
+		    {},				/* Param read.  */
+		    0,				/* num_param_writes.  */
+		    {{0, -1, 0}},		/* Param written.  */
+		    AO_FUNCTION_ERRNO,		/* flags.  */
+		 };
+	  ret_info.writes[0].size
+		 = tree_to_uhwi (TYPE_SIZE_UNIT (ptr_type_node));
+	  *info = ret_info;
+	  return true;
+	}
+      /* The following builtins do not read from memory.  */
+      case BUILT_IN_STACK_RESTORE:
+	{
+	  const static struct ao_function_info ret_info
+	       = {
+		    0,				/* num_param_reads.  */
+		    {},				/* Param read.  */
+		    0,				/* num_param_writes.  */
+		    {},				/* Param written.  */
+		    (ao_function_flags)0,	/* flags.  */
+		 };
+	  *info = ret_info;
+	  return true;
+	}
+      /* __sync_* builtins and some OpenMP builtins act as threading
+	 barriers.  */
+#undef DEF_SYNC_BUILTIN
+#define DEF_SYNC_BUILTIN(ENUM, NAME, TYPE, ATTRS) case ENUM:
+#include "sync-builtins.def"
+#undef DEF_SYNC_BUILTIN
+      case BUILT_IN_GOMP_ATOMIC_START:
+      case BUILT_IN_GOMP_ATOMIC_END:
+      case BUILT_IN_GOMP_BARRIER:
+      case BUILT_IN_GOMP_BARRIER_CANCEL:
+      case BUILT_IN_GOMP_TASKWAIT:
+      case BUILT_IN_GOMP_TASKGROUP_END:
+      case BUILT_IN_GOMP_CRITICAL_START:
+      case BUILT_IN_GOMP_CRITICAL_END:
+      case BUILT_IN_GOMP_CRITICAL_NAME_START:
+      case BUILT_IN_GOMP_CRITICAL_NAME_END:
+      case BUILT_IN_GOMP_LOOP_END:
+      case BUILT_IN_GOMP_LOOP_END_CANCEL:
+      case BUILT_IN_GOMP_ORDERED_START:
+      case BUILT_IN_GOMP_ORDERED_END:
+      case BUILT_IN_GOMP_SECTIONS_END:
+      case BUILT_IN_GOMP_SECTIONS_END_CANCEL:
+      case BUILT_IN_GOMP_SINGLE_COPY_START:
+      case BUILT_IN_GOMP_SINGLE_COPY_END:
+	{
+	  const static struct ao_function_info ret_info
+	       = {
+		    -1,				/* num_param_reads.  */
+		    {},				/* Param read.  */
+		    -1,				/* num_param_writes.  */
+		    {},				/* Param written.  */
+		    AO_FUNCTION_BARRIER,	/* flags.  */
+		 };
+	  *info = ret_info;
+	  return true;
+	}
+
+      default:
+	return false;
+    }
+}
+
 /* If the call CALL may use the memory reference REF return true,
    otherwise return false.  */
 
@@ -2574,219 +3075,37 @@  ref_maybe_used_by_call_p_1 (gcall *call, ao_ref *ref, bool tbaa_p)
   /* 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.  */
+  struct ao_function_info info;
   if (callee != NULL_TREE
-      && gimple_call_builtin_p (call, BUILT_IN_NORMAL))
-    switch (DECL_FUNCTION_CODE (callee))
-      {
-	/* All the following functions read memory pointed to by
-	   their second argument.  strcat/strncat additionally
-	   reads memory pointed to by the first argument.  */
-	case BUILT_IN_STRCAT:
-	case BUILT_IN_STRNCAT:
-	  {
-	    ao_ref dref;
-	    ao_ref_init_from_ptr_and_size (&dref,
-					   gimple_call_arg (call, 0),
-					   NULL_TREE);
-	    if (refs_may_alias_p_1 (&dref, ref, false))
-	      return true;
-	  }
-	  /* FALLTHRU */
-	case BUILT_IN_STRCPY:
-	case BUILT_IN_STRNCPY:
-	case BUILT_IN_MEMCPY:
-	case BUILT_IN_MEMMOVE:
-	case BUILT_IN_MEMPCPY:
-	case BUILT_IN_STPCPY:
-	case BUILT_IN_STPNCPY:
-	case BUILT_IN_TM_MEMCPY:
-	case BUILT_IN_TM_MEMMOVE:
-	  {
-	    ao_ref dref;
-	    tree size = NULL_TREE;
-	    if (gimple_call_num_args (call) == 3)
-	      size = gimple_call_arg (call, 2);
-	    ao_ref_init_from_ptr_and_size (&dref,
-					   gimple_call_arg (call, 1),
-					   size);
-	    return refs_may_alias_p_1 (&dref, ref, false);
-	  }
-	case BUILT_IN_STRCAT_CHK:
-	case BUILT_IN_STRNCAT_CHK:
-	  {
-	    ao_ref dref;
-	    ao_ref_init_from_ptr_and_size (&dref,
-					   gimple_call_arg (call, 0),
-					   NULL_TREE);
-	    if (refs_may_alias_p_1 (&dref, ref, false))
-	      return true;
-	  }
-	  /* FALLTHRU */
-	case BUILT_IN_STRCPY_CHK:
-	case BUILT_IN_STRNCPY_CHK:
-	case BUILT_IN_MEMCPY_CHK:
-	case BUILT_IN_MEMMOVE_CHK:
-	case BUILT_IN_MEMPCPY_CHK:
-	case BUILT_IN_STPCPY_CHK:
-	case BUILT_IN_STPNCPY_CHK:
-	  {
-	    ao_ref dref;
-	    tree size = NULL_TREE;
-	    if (gimple_call_num_args (call) == 4)
-	      size = gimple_call_arg (call, 2);
-	    ao_ref_init_from_ptr_and_size (&dref,
-					   gimple_call_arg (call, 1),
-					   size);
-	    return refs_may_alias_p_1 (&dref, ref, false);
-	  }
-	case BUILT_IN_BCOPY:
-	  {
-	    ao_ref dref;
-	    tree size = gimple_call_arg (call, 2);
-	    ao_ref_init_from_ptr_and_size (&dref,
-					   gimple_call_arg (call, 0),
-					   size);
-	    return refs_may_alias_p_1 (&dref, ref, false);
-	  }
-
-	/* The following functions read memory pointed to by their
-	   first argument.  */
-	CASE_BUILT_IN_TM_LOAD (1):
-	CASE_BUILT_IN_TM_LOAD (2):
-	CASE_BUILT_IN_TM_LOAD (4):
-	CASE_BUILT_IN_TM_LOAD (8):
-	CASE_BUILT_IN_TM_LOAD (FLOAT):
-	CASE_BUILT_IN_TM_LOAD (DOUBLE):
-	CASE_BUILT_IN_TM_LOAD (LDOUBLE):
-	CASE_BUILT_IN_TM_LOAD (M64):
-	CASE_BUILT_IN_TM_LOAD (M128):
-	CASE_BUILT_IN_TM_LOAD (M256):
-	case BUILT_IN_TM_LOG:
-	case BUILT_IN_TM_LOG_1:
-	case BUILT_IN_TM_LOG_2:
-	case BUILT_IN_TM_LOG_4:
-	case BUILT_IN_TM_LOG_8:
-	case BUILT_IN_TM_LOG_FLOAT:
-	case BUILT_IN_TM_LOG_DOUBLE:
-	case BUILT_IN_TM_LOG_LDOUBLE:
-	case BUILT_IN_TM_LOG_M64:
-	case BUILT_IN_TM_LOG_M128:
-	case BUILT_IN_TM_LOG_M256:
-	  return ptr_deref_may_alias_ref_p_1 (gimple_call_arg (call, 0), ref);
-
-	/* These read memory pointed to by the first argument.  */
-	case BUILT_IN_STRDUP:
-	case BUILT_IN_STRNDUP:
-	case BUILT_IN_REALLOC:
-	  {
-	    ao_ref dref;
-	    tree size = NULL_TREE;
-	    if (gimple_call_num_args (call) == 2)
-	      size = gimple_call_arg (call, 1);
-	    ao_ref_init_from_ptr_and_size (&dref,
-					   gimple_call_arg (call, 0),
-					   size);
-	    return refs_may_alias_p_1 (&dref, ref, false);
-	  }
-	/* These read memory pointed to by the first argument.  */
-	case BUILT_IN_INDEX:
-	case BUILT_IN_STRCHR:
-	case BUILT_IN_STRRCHR:
-	  {
-	    ao_ref dref;
-	    ao_ref_init_from_ptr_and_size (&dref,
-					   gimple_call_arg (call, 0),
-					   NULL_TREE);
-	    return refs_may_alias_p_1 (&dref, ref, false);
-	  }
-	/* These read memory pointed to by the first argument with size
-	   in the third argument.  */
-	case BUILT_IN_MEMCHR:
-	  {
-	    ao_ref dref;
-	    ao_ref_init_from_ptr_and_size (&dref,
-					   gimple_call_arg (call, 0),
-					   gimple_call_arg (call, 2));
-	    return refs_may_alias_p_1 (&dref, ref, false);
-	  }
-	/* These read memory pointed to by the first and second arguments.  */
-	case BUILT_IN_STRSTR:
-	case BUILT_IN_STRPBRK:
-	  {
-	    ao_ref dref;
-	    ao_ref_init_from_ptr_and_size (&dref,
-					   gimple_call_arg (call, 0),
-					   NULL_TREE);
-	    if (refs_may_alias_p_1 (&dref, ref, false))
-	      return true;
-	    ao_ref_init_from_ptr_and_size (&dref,
-					   gimple_call_arg (call, 1),
-					   NULL_TREE);
-	    return refs_may_alias_p_1 (&dref, ref, false);
-	  }
-
-	/* The following builtins do not read from memory.  */
-	case BUILT_IN_FREE:
-	case BUILT_IN_MALLOC:
-	case BUILT_IN_POSIX_MEMALIGN:
-	case BUILT_IN_ALIGNED_ALLOC:
-	case BUILT_IN_CALLOC:
-	CASE_BUILT_IN_ALLOCA:
-	case BUILT_IN_STACK_SAVE:
-	case BUILT_IN_STACK_RESTORE:
-	case BUILT_IN_MEMSET:
-	case BUILT_IN_TM_MEMSET:
-	case BUILT_IN_MEMSET_CHK:
-	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_SINCOS:
-	case BUILT_IN_SINCOSF:
-	case BUILT_IN_SINCOSL:
-	case BUILT_IN_ASSUME_ALIGNED:
-	case BUILT_IN_VA_END:
+      && gimple_call_builtin_p (call, BUILT_IN_NORMAL)
+      && (ao_classify_builtin (callee, &info)))
+    {
+      if (info.flags & AO_FUNCTION_BARRIER)
+	return true;
+      if (info.num_param_reads >= 0)
+	{
+	  for (int i = 0; i < info.num_param_reads; i++)
+	    {
+	      ao_ref dref;
+	      tree size = NULL_TREE;
+
+	      gcc_checking_assert (info.reads[i].size_param
+				   != info.reads[i].param);
+	      if (info.reads[i].size_param != -1)
+		size = gimple_call_arg (call, info.reads[i].size);
+	      else if (info.reads[i].size)
+		size = build_int_cst (size_type_node, info.reads[i].size);
+	      ao_ref_init_from_ptr_and_size (&dref,
+					     gimple_call_arg
+						 (call,
+						  info.reads[i].param),
+					     size);
+	      if (refs_may_alias_p_1 (&dref, ref, tbaa_p))
+		return true;
+	    }
 	  return false;
-	/* __sync_* builtins and some OpenMP builtins act as threading
-	   barriers.  */
-#undef DEF_SYNC_BUILTIN
-#define DEF_SYNC_BUILTIN(ENUM, NAME, TYPE, ATTRS) case ENUM:
-#include "sync-builtins.def"
-#undef DEF_SYNC_BUILTIN
-	case BUILT_IN_GOMP_ATOMIC_START:
-	case BUILT_IN_GOMP_ATOMIC_END:
-	case BUILT_IN_GOMP_BARRIER:
-	case BUILT_IN_GOMP_BARRIER_CANCEL:
-	case BUILT_IN_GOMP_TASKWAIT:
-	case BUILT_IN_GOMP_TASKGROUP_END:
-	case BUILT_IN_GOMP_CRITICAL_START:
-	case BUILT_IN_GOMP_CRITICAL_END:
-	case BUILT_IN_GOMP_CRITICAL_NAME_START:
-	case BUILT_IN_GOMP_CRITICAL_NAME_END:
-	case BUILT_IN_GOMP_LOOP_END:
-	case BUILT_IN_GOMP_LOOP_END_CANCEL:
-	case BUILT_IN_GOMP_ORDERED_START:
-	case BUILT_IN_GOMP_ORDERED_END:
-	case BUILT_IN_GOMP_SECTIONS_END:
-	case BUILT_IN_GOMP_SECTIONS_END_CANCEL:
-	case BUILT_IN_GOMP_SINGLE_COPY_START:
-	case BUILT_IN_GOMP_SINGLE_COPY_END:
-	  return true;
-
-	default:
-	  /* Fallthru to general call handling.  */;
-      }
+	}
+    }
 
   /* Check if base is a global static variable that is not read
      by the function.  */
@@ -2961,7 +3280,9 @@  call_may_clobber_ref_p_1 (gcall *call, ao_ref *ref, bool tbaa_p)
 	  modref_summary *summary = get_modref_function_summary (node);
 	  if (summary)
 	    {
-	      if (!modref_may_conflict (call, summary->stores, ref, tbaa_p))
+	      if (!modref_may_conflict (call, summary->stores, ref, tbaa_p)
+		  && (!summary->writes_errno
+		      || !targetm.ref_may_alias_errno (ref)))
 		{
 		  alias_stats.modref_clobber_no_alias++;
 		  if (dump_file && (dump_flags & TDF_DETAILS))
@@ -3016,205 +3337,43 @@  call_may_clobber_ref_p_1 (gcall *call, ao_ref *ref, bool tbaa_p)
       && SSA_NAME_POINTS_TO_READONLY_MEMORY (TREE_OPERAND (base, 0)))
     return false;
 
+  struct ao_function_info info;
   /* 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.  */
+     escape points.  */
   if (callee != NULL_TREE
-      && gimple_call_builtin_p (call, 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_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:
-	case BUILT_IN_MEMSET:
-	case BUILT_IN_TM_MEMSET:
-	CASE_BUILT_IN_TM_STORE (1):
-	CASE_BUILT_IN_TM_STORE (2):
-	CASE_BUILT_IN_TM_STORE (4):
-	CASE_BUILT_IN_TM_STORE (8):
-	CASE_BUILT_IN_TM_STORE (FLOAT):
-	CASE_BUILT_IN_TM_STORE (DOUBLE):
-	CASE_BUILT_IN_TM_STORE (LDOUBLE):
-	CASE_BUILT_IN_TM_STORE (M64):
-	CASE_BUILT_IN_TM_STORE (M128):
-	CASE_BUILT_IN_TM_STORE (M256):
-	case BUILT_IN_TM_MEMCPY:
-	case BUILT_IN_TM_MEMMOVE:
-	  {
-	    ao_ref dref;
-	    tree size = NULL_TREE;
-	    /* Don't pass in size for strncat, as the maximum size
-	       is strlen (dest) + n + 1 instead of n, resp.
-	       n + 1 at dest + strlen (dest), but strlen (dest) isn't
-	       known.  */
-	    if (gimple_call_num_args (call) == 3
-		&& DECL_FUNCTION_CODE (callee) != BUILT_IN_STRNCAT)
-	      size = gimple_call_arg (call, 2);
-	    ao_ref_init_from_ptr_and_size (&dref,
-					   gimple_call_arg (call, 0),
-					   size);
-	    return refs_may_alias_p_1 (&dref, ref, false);
-	  }
-	case BUILT_IN_STRCPY_CHK:
-	case BUILT_IN_STRNCPY_CHK:
-	case BUILT_IN_MEMCPY_CHK:
-	case BUILT_IN_MEMMOVE_CHK:
-	case BUILT_IN_MEMPCPY_CHK:
-	case BUILT_IN_STPCPY_CHK:
-	case BUILT_IN_STPNCPY_CHK:
-	case BUILT_IN_STRCAT_CHK:
-	case BUILT_IN_STRNCAT_CHK:
-	case BUILT_IN_MEMSET_CHK:
-	  {
-	    ao_ref dref;
-	    tree size = NULL_TREE;
-	    /* Don't pass in size for __strncat_chk, as the maximum size
-	       is strlen (dest) + n + 1 instead of n, resp.
-	       n + 1 at dest + strlen (dest), but strlen (dest) isn't
-	       known.  */
-	    if (gimple_call_num_args (call) == 4
-		&& DECL_FUNCTION_CODE (callee) != BUILT_IN_STRNCAT_CHK)
-	      size = gimple_call_arg (call, 2);
-	    ao_ref_init_from_ptr_and_size (&dref,
-					   gimple_call_arg (call, 0),
-					   size);
-	    return refs_may_alias_p_1 (&dref, ref, false);
-	  }
-	case BUILT_IN_BCOPY:
-	  {
-	    ao_ref dref;
-	    tree size = gimple_call_arg (call, 2);
-	    ao_ref_init_from_ptr_and_size (&dref,
-					   gimple_call_arg (call, 1),
-					   size);
-	    return refs_may_alias_p_1 (&dref, ref, false);
-	  }
-	/* Allocating memory does not have any side-effects apart from
-	   being the definition point for the pointer.  */
-	case BUILT_IN_MALLOC:
-	case BUILT_IN_ALIGNED_ALLOC:
-	case BUILT_IN_CALLOC:
-	case BUILT_IN_STRDUP:
-	case BUILT_IN_STRNDUP:
-	  /* Unix98 specifies that errno is set on allocation failure.  */
-	  if (flag_errno_math
-	      && targetm.ref_may_alias_errno (ref))
-	    return true;
-	  return false;
-	case BUILT_IN_STACK_SAVE:
-	CASE_BUILT_IN_ALLOCA:
-	case BUILT_IN_ASSUME_ALIGNED:
+      && gimple_call_builtin_p (call, BUILT_IN_NORMAL)
+      && (ao_classify_builtin (callee, &info)))
+    {
+      if (info.flags & AO_FUNCTION_BARRIER)
+	return true;
+      if ((info.flags & AO_FUNCTION_ERRNO)
+	  && flag_errno_math
+	  && targetm.ref_may_alias_errno (ref))
+	return true;
+      if (info.num_param_writes >= 0)
+	{
+	  for (int i = 0; i < info.num_param_writes; i++)
+	    {
+	      ao_ref dref;
+	      tree size = NULL_TREE;
+
+	      gcc_checking_assert (info.writes[i].size_param
+				   != info.writes[i].param);
+	      if (info.writes[i].size_param != -1)
+		size = gimple_call_arg (call, info.writes[i].size_param);
+	      else if (info.writes[i].size)
+		size = build_int_cst (size_type_node, info.writes[i].size);
+	      ao_ref_init_from_ptr_and_size (&dref,
+					     gimple_call_arg
+						 (call,
+						  info.writes[i].param),
+					     size);
+	      if (refs_may_alias_p_1 (&dref, ref, tbaa_p))
+		return true;
+	    }
 	  return false;
-	/* But posix_memalign stores a pointer into the memory pointed to
-	   by its first argument.  */
-	case BUILT_IN_POSIX_MEMALIGN:
-	  {
-	    tree ptrptr = gimple_call_arg (call, 0);
-	    ao_ref dref;
-	    ao_ref_init_from_ptr_and_size (&dref, ptrptr,
-					   TYPE_SIZE_UNIT (ptr_type_node));
-	    return (refs_may_alias_p_1 (&dref, ref, false)
-		    || (flag_errno_math
-			&& targetm.ref_may_alias_errno (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.  */
-	case BUILT_IN_FREE:
-	case BUILT_IN_VA_END:
-	  {
-	    tree ptr = gimple_call_arg (call, 0);
-	    return ptr_deref_may_alias_ref_p_1 (ptr, ref);
-	  }
-	/* Realloc serves both as allocation point and deallocation point.  */
-	case BUILT_IN_REALLOC:
-	  {
-	    tree ptr = gimple_call_arg (call, 0);
-	    /* Unix98 specifies that errno is set on allocation failure.  */
-	    return ((flag_errno_math
-		     && targetm.ref_may_alias_errno (ref))
-		    || ptr_deref_may_alias_ref_p_1 (ptr, ref));
-	  }
-	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:
-	  {
-	    tree out = gimple_call_arg (call, 1);
-	    if (ptr_deref_may_alias_ref_p_1 (out, ref))
-	      return true;
-	    if (flag_errno_math)
-	      break;
-	    return false;
-	  }
-	case BUILT_IN_FREXP:
-	case BUILT_IN_FREXPF:
-	case BUILT_IN_FREXPL:
-	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_1 (out, ref);
-	  }
-	case BUILT_IN_REMQUO:
-	case BUILT_IN_REMQUOF:
-	case BUILT_IN_REMQUOL:
-	  {
-	    tree out = gimple_call_arg (call, 2);
-	    if (ptr_deref_may_alias_ref_p_1 (out, ref))
-	      return true;
-	    if (flag_errno_math)
-	      break;
-	    return false;
-	  }
-	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);
-	    return (ptr_deref_may_alias_ref_p_1 (sin, ref)
-		    || ptr_deref_may_alias_ref_p_1 (cos, ref));
-	  }
-	/* __sync_* builtins and some OpenMP builtins act as threading
-	   barriers.  */
-#undef DEF_SYNC_BUILTIN
-#define DEF_SYNC_BUILTIN(ENUM, NAME, TYPE, ATTRS) case ENUM:
-#include "sync-builtins.def"
-#undef DEF_SYNC_BUILTIN
-	case BUILT_IN_GOMP_ATOMIC_START:
-	case BUILT_IN_GOMP_ATOMIC_END:
-	case BUILT_IN_GOMP_BARRIER:
-	case BUILT_IN_GOMP_BARRIER_CANCEL:
-	case BUILT_IN_GOMP_TASKWAIT:
-	case BUILT_IN_GOMP_TASKGROUP_END:
-	case BUILT_IN_GOMP_CRITICAL_START:
-	case BUILT_IN_GOMP_CRITICAL_END:
-	case BUILT_IN_GOMP_CRITICAL_NAME_START:
-	case BUILT_IN_GOMP_CRITICAL_NAME_END:
-	case BUILT_IN_GOMP_LOOP_END:
-	case BUILT_IN_GOMP_LOOP_END_CANCEL:
-	case BUILT_IN_GOMP_ORDERED_START:
-	case BUILT_IN_GOMP_ORDERED_END:
-	case BUILT_IN_GOMP_SECTIONS_END:
-	case BUILT_IN_GOMP_SECTIONS_END_CANCEL:
-	case BUILT_IN_GOMP_SINGLE_COPY_START:
-	case BUILT_IN_GOMP_SINGLE_COPY_END:
-	  return true;
-	default:
-	  /* Fallthru to general call handling.  */;
-      }
+	}
+    }
 
   /* Check if base is a global static variable that is not written
      by the function.  */