Export info about side effects of builtins out of tree-ssa-alias.c
Jan Hubicka
hubicka@ucw.cz
Mon Sep 28 08:32:07 GMT 2020
> 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
More information about the Gcc-patches
mailing list