From patchwork Sun Sep 27 22:16:05 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jan Hubicka X-Patchwork-Id: 1372180 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=gcc.gnu.org (client-ip=2620:52:3:1:0:246e:9693:128c; helo=sourceware.org; envelope-from=gcc-patches-bounces@gcc.gnu.org; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=ucw.cz Received: from sourceware.org (server2.sourceware.org [IPv6:2620:52:3:1:0:246e:9693:128c]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4C00Ng12T9z9s1t for ; Mon, 28 Sep 2020 08:16:17 +1000 (AEST) Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 5AADD3892454; Sun, 27 Sep 2020 22:16:14 +0000 (GMT) X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from nikam.ms.mff.cuni.cz (nikam.ms.mff.cuni.cz [195.113.20.16]) by sourceware.org (Postfix) with ESMTPS id 13E6A385701E for ; Sun, 27 Sep 2020 22:16:10 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.3.2 sourceware.org 13E6A385701E 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 9C77B282ADE; Mon, 28 Sep 2020 00:16:05 +0200 (CEST) Date: Mon, 28 Sep 2020 00:16:05 +0200 From: Jan Hubicka To: gcc-patches@gcc.gnu.org, d@dcepelik.cz, rguenther@suse.de Subject: Export info about side effects of builtins out of tree-ssa-alias.c Message-ID: <20200927221605.GD52458@kam.mff.cuni.cz> MIME-Version: 1.0 Content-Disposition: inline User-Agent: Mutt/1.10.1 (2018-07-13) X-Spam-Status: No, score=-14.9 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: , Errors-To: gcc-patches-bounces@gcc.gnu.org Sender: "Gcc-patches" Hi, ipa-reference, ipa-pure-const and ipa-modref could use the knowledge about bulitins which is currently harwired into ref_maybe_used_by_call_p_1, call_may_clobber_ref_p_1 and the PTA computation. This patch breaks out logic implemented in the first two into a form of a simple descriptor that can be used by the IPA passes (and other code). I was considering an option of putting this into def file but I do not think it is feasible without cluttering it quite a lot. For ipa-modref I implemented dump informing about missing builtins. strlen, sqrt and exp seems common offenders, but that can be handled incrementally if the approach looks reasonable. I would also look adding the description for PTA (perhaps with some special cases remainig since it is more ad-hoc) Bootstrapped/regtested x86_64-linux, OK? gcc/ChangeLog: 2020-09-28 Jan Hubicka * 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. */