From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from nikam.ms.mff.cuni.cz (nikam.ms.mff.cuni.cz [195.113.20.16]) by sourceware.org (Postfix) with ESMTPS id EFA673857C59 for ; Mon, 28 Sep 2020 08:32:09 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.3.2 sourceware.org EFA673857C59 Authentication-Results: sourceware.org; dmarc=none (p=none dis=none) header.from=ucw.cz Authentication-Results: sourceware.org; spf=none smtp.mailfrom=hubicka@kam.mff.cuni.cz Received: by nikam.ms.mff.cuni.cz (Postfix, from userid 16202) id 898AE282AD6; Mon, 28 Sep 2020 10:32:07 +0200 (CEST) Date: Mon, 28 Sep 2020 10:32:07 +0200 From: Jan Hubicka To: Richard Biener Cc: gcc-patches@gcc.gnu.org, d@dcepelik.cz Subject: Re: Export info about side effects of builtins out of tree-ssa-alias.c Message-ID: <20200928083207.GD34784@kam.mff.cuni.cz> References: <20200927221605.GD52458@kam.mff.cuni.cz> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline In-Reply-To: User-Agent: Mutt/1.10.1 (2018-07-13) X-Spam-Status: No, score=-14.7 required=5.0 tests=BAYES_00, GIT_PATCH_0, HEADER_FROM_DIFFERENT_DOMAINS, KAM_DMARC_STATUS, KAM_LAZY_DOMAIN_SECURITY, RCVD_IN_MSPIKE_H3, RCVD_IN_MSPIKE_WL, SPF_HELO_NONE, SPF_NONE, TXREP autolearn=ham autolearn_force=no version=3.4.2 X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on server2.sourceware.org X-BeenThere: gcc-patches@gcc.gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gcc-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 28 Sep 2020 08:32:13 -0000 > 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 > > > > * 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 > SUSE Software Solutions Germany GmbH, Maxfeldstrasse 5, 90409 Nuernberg, > Germany; GF: Felix Imend