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 |
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. */ >
> 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
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 > >
> > 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
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 > >
> 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
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 --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. */