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  <hubi...@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 <rguent...@suse.de>
SUSE Software Solutions Germany GmbH, Maxfeldstrasse 5, 90409 Nuernberg,
Germany; GF: Felix Imend

Reply via email to