Extend builtin fnspecs
* attr-fnspec.h: Update toplevel comment. (attr_fnspec::attr_fnspec): New constructor. (attr_fnspec::arg_read_p, attr_fnspec::arg_written_p, attr_fnspec::arg_access_size_given_by_arg_p, attr_fnspec::arg_single_access_p attr_fnspec::loads_known_p attr_fnspec::stores_known_p, attr_fnspec::clobbers_errno_p): New member functions. (gimple_call_fnspec): Declare. (builtin_fnspec): Declare. * builtins.c: Include attr-fnspec.h (builtin_fnspec): New function. * builtins.def (BUILT_IN_MEMCPY): Do not specify RET1 fnspec. (BUILT_IN_MEMMOVE): Do not specify RET1 fnspec. (BUILT_IN_MEMSET): Do not specify RET1 fnspec. (BUILT_IN_STRCAT): Do not specify RET1 fnspec. (BUILT_IN_STRCPY): Do not specify RET1 fnspec. (BUILT_IN_STRNCAT): Do not specify RET1 fnspec. (BUILT_IN_STRNCPY): Do not specify RET1 fnspec. (BUILT_IN_MEMCPY_CHK): Do not specify RET1 fnspec. (BUILT_IN_MEMMOVE_CHK): Do not specify RET1 fnspec. (BUILT_IN_MEMSET_CHK): Do not specify RET1 fnspec. (BUILT_IN_STRCAT_CHK): Do not specify RET1 fnspec. (BUILT_IN_STRCPY_CHK): Do not specify RET1 fnspec. (BUILT_IN_STRNCAT_CHK): Do not specify RET1 fnspec. (BUILT_IN_STRNCPY_CHK): Do not specify RET1 fnspec. * gimple.c (gimple_call_fnspec): Return attr_fnspec. (gimple_call_arg_flags): Update. (gimple_call_return_flags): Update. * tree-ssa-alias.c (check_fnspec): New function. (ref_maybe_used_by_call_p_1): Use fnspec for builtin handling. (call_may_clobber_ref_p_1): Likewise. (attr_fnspec::verify): Update verifier. * calls.c (decl_fnspec): New function. (decl_return_flags): Use it.
This commit is contained in:
parent
2118438f49
commit
4f8cfb4288
6 changed files with 452 additions and 463 deletions
|
@ -27,11 +27,18 @@
|
|||
'.' specifies that nothing is known.
|
||||
character 1 specifies additional function properties
|
||||
' ' specifies that nothing is known
|
||||
'p' or 'P' specifies that function is pure except for described side
|
||||
effects.
|
||||
'c' or 'C' specifies that function is const except for described side
|
||||
effects.
|
||||
The uppercase letter in addition specifies that function clobbers errno.
|
||||
|
||||
character 2+2i specifies properties of argument number i as follows:
|
||||
'x' or 'X' specifies that parameter is unused.
|
||||
'r' or 'R' specifies that the memory pointed to by the parameter is only
|
||||
read and does not escape
|
||||
'o' or 'O' specifies that the memory pointed to by the parameter is only
|
||||
written and does not escape
|
||||
'w' or 'W' specifies that the memory pointed to by the parameter does not
|
||||
escape
|
||||
'.' specifies that nothing is known.
|
||||
|
@ -42,6 +49,10 @@
|
|||
character 3+2i specifies additional properties of argument number i
|
||||
as follows:
|
||||
' ' nothing is known
|
||||
't' the size of value written/read corresponds to the size of
|
||||
of the pointed-to type of the argument type
|
||||
'1'...'9' the size of value written/read is given by the specified
|
||||
argument
|
||||
*/
|
||||
|
||||
#ifndef ATTR_FNSPEC_H
|
||||
|
@ -72,6 +83,12 @@ public:
|
|||
if (flag_checking)
|
||||
verify ();
|
||||
}
|
||||
attr_fnspec (const char *str)
|
||||
: str (str), len (strlen (str))
|
||||
{
|
||||
if (flag_checking)
|
||||
verify ();
|
||||
}
|
||||
attr_fnspec (const_tree identifier)
|
||||
: str (TREE_STRING_POINTER (identifier)),
|
||||
len (TREE_STRING_LENGTH (identifier))
|
||||
|
@ -79,6 +96,17 @@ public:
|
|||
if (flag_checking)
|
||||
verify ();
|
||||
}
|
||||
attr_fnspec ()
|
||||
: str (NULL), len (0)
|
||||
{
|
||||
}
|
||||
|
||||
/* Return true if fn spec is known. */
|
||||
bool
|
||||
known_p ()
|
||||
{
|
||||
return len;
|
||||
}
|
||||
|
||||
/* Return true if arg I is specified. */
|
||||
bool
|
||||
|
@ -94,7 +122,7 @@ public:
|
|||
{
|
||||
unsigned int idx = arg_idx (i);
|
||||
gcc_checking_assert (arg_specified_p (i));
|
||||
return str[idx] == 'R' || str[idx] == 'W';
|
||||
return str[idx] == 'R' || str[idx] == 'O' || str[idx] == 'W';
|
||||
}
|
||||
|
||||
/* True if argument is used. */
|
||||
|
@ -115,6 +143,53 @@ public:
|
|||
return str[idx] == 'r' || str[idx] == 'R';
|
||||
}
|
||||
|
||||
/* True if memory reached by the argument is read (directly or indirectly) */
|
||||
bool
|
||||
arg_maybe_read_p (unsigned int i)
|
||||
{
|
||||
unsigned int idx = arg_idx (i);
|
||||
gcc_checking_assert (arg_specified_p (i));
|
||||
return str[idx] != 'o' && str[idx] != 'O'
|
||||
&& str[idx] != 'x' && str[idx] != 'X';
|
||||
}
|
||||
|
||||
/* True if memory reached by the argument is written.
|
||||
(directly or indirectly) */
|
||||
bool
|
||||
arg_maybe_written_p (unsigned int i)
|
||||
{
|
||||
unsigned int idx = arg_idx (i);
|
||||
gcc_checking_assert (arg_specified_p (i));
|
||||
return str[idx] != 'r' && str[idx] != 'R'
|
||||
&& str[idx] != 'x' && str[idx] != 'X';
|
||||
}
|
||||
|
||||
/* Return true if load of memory pointed to by argument I is specified
|
||||
by another argument. In this case set ARG. */
|
||||
bool
|
||||
arg_max_access_size_given_by_arg_p (unsigned int i, unsigned int *arg)
|
||||
{
|
||||
unsigned int idx = arg_idx (i);
|
||||
gcc_checking_assert (arg_specified_p (i));
|
||||
if (str[idx + 1] >= '1' && str[idx + 1] <= '9')
|
||||
{
|
||||
*arg = str[idx + 1] - '1';
|
||||
return true;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Return true if the pointed-to type of the argument correspond to the
|
||||
size of the memory acccess. */
|
||||
bool
|
||||
arg_access_size_given_by_type_p (unsigned int i)
|
||||
{
|
||||
unsigned int idx = arg_idx (i);
|
||||
gcc_checking_assert (arg_specified_p (i));
|
||||
return str[idx + 1] == 't';
|
||||
}
|
||||
|
||||
/* True if the argument does not escape. */
|
||||
bool
|
||||
arg_noescape_p (unsigned int i)
|
||||
|
@ -122,7 +197,8 @@ public:
|
|||
unsigned int idx = arg_idx (i);
|
||||
gcc_checking_assert (arg_specified_p (i));
|
||||
return str[idx] == 'w' || str[idx] == 'W'
|
||||
|| str[idx] == 'R' || str[idx] == 'r';
|
||||
|| str[idx] == 'r' || str[idx] == 'R'
|
||||
|| str[idx] == 'o' || str[idx] == 'O';
|
||||
}
|
||||
|
||||
/* Return true if function returns value of its parameter. If ARG_NO is
|
||||
|
@ -147,8 +223,32 @@ public:
|
|||
return str[0] == 'm';
|
||||
}
|
||||
|
||||
/* Return true if all memory read by the function is specified by fnspec. */
|
||||
bool
|
||||
global_memory_read_p ()
|
||||
{
|
||||
return str[1] != 'c' && str[1] != 'C';
|
||||
}
|
||||
|
||||
/* Return true if all memory written by the function
|
||||
is specified by fnspec. */
|
||||
bool
|
||||
global_memory_written_p ()
|
||||
{
|
||||
return str[1] != 'c' && str[1] != 'C' && str[1] != 'p' && str[1] != 'P';
|
||||
}
|
||||
|
||||
bool
|
||||
errno_maybe_written_p ()
|
||||
{
|
||||
return str[1] == 'C' || str[1] == 'P';
|
||||
}
|
||||
|
||||
/* Check validity of the string. */
|
||||
void verify ();
|
||||
};
|
||||
|
||||
extern attr_fnspec gimple_call_fnspec (const gcall *stmt);
|
||||
extern attr_fnspec builtin_fnspec (tree);
|
||||
|
||||
#endif /* ATTR_FNSPEC_H */
|
||||
|
|
163
gcc/builtins.c
163
gcc/builtins.c
|
@ -76,6 +76,7 @@ along with GCC; see the file COPYING3. If not see
|
|||
#include "gimple-ssa.h"
|
||||
#include "tree-ssa-live.h"
|
||||
#include "tree-outof-ssa.h"
|
||||
#include "attr-fnspec.h"
|
||||
|
||||
struct target_builtins default_target_builtins;
|
||||
#if SWITCHABLE_TARGET
|
||||
|
@ -12913,3 +12914,165 @@ access_ref::offset_bounded () const
|
|||
tree max = TYPE_MAX_VALUE (ptrdiff_type_node);
|
||||
return wi::to_offset (min) <= offrng[0] && offrng[1] <= wi::to_offset (max);
|
||||
}
|
||||
|
||||
/* 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. */
|
||||
|
||||
attr_fnspec
|
||||
builtin_fnspec (tree callee)
|
||||
{
|
||||
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:
|
||||
case BUILT_IN_STRCAT_CHK:
|
||||
return "1cW R ";
|
||||
case BUILT_IN_STRNCAT:
|
||||
case BUILT_IN_STRNCAT_CHK:
|
||||
return "1cW R3";
|
||||
case BUILT_IN_STRCPY:
|
||||
case BUILT_IN_STRCPY_CHK:
|
||||
return "1cO R ";
|
||||
case BUILT_IN_STPCPY:
|
||||
case BUILT_IN_STPCPY_CHK:
|
||||
return ".cO R ";
|
||||
case BUILT_IN_STRNCPY:
|
||||
case BUILT_IN_MEMCPY:
|
||||
case BUILT_IN_MEMMOVE:
|
||||
case BUILT_IN_TM_MEMCPY:
|
||||
case BUILT_IN_TM_MEMMOVE:
|
||||
case BUILT_IN_STRNCPY_CHK:
|
||||
case BUILT_IN_MEMCPY_CHK:
|
||||
case BUILT_IN_MEMMOVE_CHK:
|
||||
return "1cO3R3";
|
||||
case BUILT_IN_MEMPCPY:
|
||||
case BUILT_IN_MEMPCPY_CHK:
|
||||
return ".cO3R3";
|
||||
case BUILT_IN_STPNCPY:
|
||||
case BUILT_IN_STPNCPY_CHK:
|
||||
return ".cO3R3";
|
||||
case BUILT_IN_BCOPY:
|
||||
return ".cR3O3";
|
||||
|
||||
/* 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 ".cR ";
|
||||
|
||||
case BUILT_IN_INDEX:
|
||||
case BUILT_IN_STRCHR:
|
||||
case BUILT_IN_STRRCHR:
|
||||
return ".cR ";
|
||||
|
||||
/* 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:
|
||||
return "mCR ";
|
||||
case BUILT_IN_STRNDUP:
|
||||
return "mCR2";
|
||||
/* 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:
|
||||
return "mC";
|
||||
CASE_BUILT_IN_ALLOCA:
|
||||
return "mc";
|
||||
/* These read memory pointed to by the first argument with size
|
||||
in the third argument. */
|
||||
case BUILT_IN_MEMCHR:
|
||||
return ".cR3";
|
||||
/* These read memory pointed to by the first and second arguments. */
|
||||
case BUILT_IN_STRSTR:
|
||||
case BUILT_IN_STRPBRK:
|
||||
return ".cR R ";
|
||||
/* 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_STACK_RESTORE:
|
||||
case BUILT_IN_FREE:
|
||||
return ".co ";
|
||||
case BUILT_IN_VA_END:
|
||||
return ".cO ";
|
||||
/* Realloc serves both as allocation point and deallocation point. */
|
||||
case BUILT_IN_REALLOC:
|
||||
return ".cw ";
|
||||
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:
|
||||
return ".C. Ot";
|
||||
case BUILT_IN_FREXP:
|
||||
case BUILT_IN_FREXPF:
|
||||
case BUILT_IN_FREXPL:
|
||||
case BUILT_IN_MODF:
|
||||
case BUILT_IN_MODFF:
|
||||
case BUILT_IN_MODFL:
|
||||
return ".c. Ot";
|
||||
case BUILT_IN_REMQUO:
|
||||
case BUILT_IN_REMQUOF:
|
||||
case BUILT_IN_REMQUOL:
|
||||
return ".c. . Ot";
|
||||
case BUILT_IN_SINCOS:
|
||||
case BUILT_IN_SINCOSF:
|
||||
case BUILT_IN_SINCOSL:
|
||||
return ".c. OtOt";
|
||||
case BUILT_IN_MEMSET:
|
||||
case BUILT_IN_MEMSET_CHK:
|
||||
case BUILT_IN_TM_MEMSET:
|
||||
return "1cO3";
|
||||
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):
|
||||
return ".cO ";
|
||||
case BUILT_IN_STACK_SAVE:
|
||||
return ".c";
|
||||
case BUILT_IN_ASSUME_ALIGNED:
|
||||
return "1cX ";
|
||||
/* But posix_memalign stores a pointer into the memory pointed to
|
||||
by its first argument. */
|
||||
case BUILT_IN_POSIX_MEMALIGN:
|
||||
return ".cOt";
|
||||
|
||||
default:
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
|
|
@ -701,26 +701,26 @@ DEF_EXT_LIB_BUILTIN (BUILT_IN_BZERO, "bzero", BT_FN_VOID_PTR_SIZE, ATTR_NOTHR
|
|||
DEF_EXT_LIB_BUILTIN (BUILT_IN_INDEX, "index", BT_FN_STRING_CONST_STRING_INT, ATTR_PURE_NOTHROW_NONNULL_LEAF)
|
||||
DEF_LIB_BUILTIN (BUILT_IN_MEMCHR, "memchr", BT_FN_PTR_CONST_PTR_INT_SIZE, ATTR_PURE_NOTHROW_NONNULL_LEAF)
|
||||
DEF_LIB_BUILTIN (BUILT_IN_MEMCMP, "memcmp", BT_FN_INT_CONST_PTR_CONST_PTR_SIZE, ATTR_PURE_NOTHROW_NONNULL_LEAF)
|
||||
DEF_LIB_BUILTIN (BUILT_IN_MEMCPY, "memcpy", BT_FN_PTR_PTR_CONST_PTR_SIZE, ATTR_RET1_NOTHROW_NONNULL_LEAF)
|
||||
DEF_LIB_BUILTIN (BUILT_IN_MEMMOVE, "memmove", BT_FN_PTR_PTR_CONST_PTR_SIZE, ATTR_RET1_NOTHROW_NONNULL_LEAF)
|
||||
DEF_LIB_BUILTIN (BUILT_IN_MEMCPY, "memcpy", BT_FN_PTR_PTR_CONST_PTR_SIZE, ATTR_NOTHROW_NONNULL_LEAF)
|
||||
DEF_LIB_BUILTIN (BUILT_IN_MEMMOVE, "memmove", BT_FN_PTR_PTR_CONST_PTR_SIZE, ATTR_NOTHROW_NONNULL_LEAF)
|
||||
DEF_EXT_LIB_BUILTIN (BUILT_IN_MEMPCPY, "mempcpy", BT_FN_PTR_PTR_CONST_PTR_SIZE, ATTR_RETNONNULL_NOTHROW_LEAF)
|
||||
DEF_LIB_BUILTIN (BUILT_IN_MEMSET, "memset", BT_FN_PTR_PTR_INT_SIZE, ATTR_RET1_NOTHROW_NONNULL_LEAF)
|
||||
DEF_LIB_BUILTIN (BUILT_IN_MEMSET, "memset", BT_FN_PTR_PTR_INT_SIZE, ATTR_NOTHROW_NONNULL_LEAF)
|
||||
DEF_EXT_LIB_BUILTIN (BUILT_IN_RINDEX, "rindex", BT_FN_STRING_CONST_STRING_INT, ATTR_PURE_NOTHROW_NONNULL_LEAF)
|
||||
DEF_EXT_LIB_BUILTIN (BUILT_IN_STPCPY, "stpcpy", BT_FN_STRING_STRING_CONST_STRING, ATTR_RETNONNULL_NOTHROW_LEAF)
|
||||
DEF_EXT_LIB_BUILTIN (BUILT_IN_STPNCPY, "stpncpy", BT_FN_STRING_STRING_CONST_STRING_SIZE, ATTR_RETNONNULL_NOTHROW_LEAF)
|
||||
DEF_EXT_LIB_BUILTIN (BUILT_IN_STRCASECMP, "strcasecmp", BT_FN_INT_CONST_STRING_CONST_STRING, ATTR_PURE_NOTHROW_NONNULL_LEAF)
|
||||
DEF_LIB_BUILTIN (BUILT_IN_STRCAT, "strcat", BT_FN_STRING_STRING_CONST_STRING, ATTR_RET1_NOTHROW_NONNULL_LEAF)
|
||||
DEF_LIB_BUILTIN (BUILT_IN_STRCAT, "strcat", BT_FN_STRING_STRING_CONST_STRING, ATTR_NOTHROW_NONNULL_LEAF)
|
||||
DEF_LIB_BUILTIN (BUILT_IN_STRCHR, "strchr", BT_FN_STRING_CONST_STRING_INT, ATTR_PURE_NOTHROW_NONNULL_LEAF)
|
||||
DEF_LIB_BUILTIN (BUILT_IN_STRCMP, "strcmp", BT_FN_INT_CONST_STRING_CONST_STRING, ATTR_PURE_NOTHROW_NONNULL_LEAF)
|
||||
DEF_LIB_BUILTIN (BUILT_IN_STRCPY, "strcpy", BT_FN_STRING_STRING_CONST_STRING, ATTR_RET1_NOTHROW_NONNULL_LEAF)
|
||||
DEF_LIB_BUILTIN (BUILT_IN_STRCPY, "strcpy", BT_FN_STRING_STRING_CONST_STRING, ATTR_NOTHROW_NONNULL_LEAF)
|
||||
DEF_LIB_BUILTIN (BUILT_IN_STRCSPN, "strcspn", BT_FN_SIZE_CONST_STRING_CONST_STRING, ATTR_PURE_NOTHROW_NONNULL_LEAF)
|
||||
DEF_C2X_BUILTIN (BUILT_IN_STRDUP, "strdup", BT_FN_STRING_CONST_STRING, ATTR_MALLOC_WARN_UNUSED_RESULT_NOTHROW_NONNULL_LEAF)
|
||||
DEF_C2X_BUILTIN (BUILT_IN_STRNDUP, "strndup", BT_FN_STRING_CONST_STRING_SIZE, ATTR_MALLOC_WARN_UNUSED_RESULT_NOTHROW_NONNULL_LEAF)
|
||||
DEF_LIB_BUILTIN (BUILT_IN_STRLEN, "strlen", BT_FN_SIZE_CONST_STRING, ATTR_PURE_NOTHROW_NONNULL_LEAF)
|
||||
DEF_EXT_LIB_BUILTIN (BUILT_IN_STRNCASECMP, "strncasecmp", BT_FN_INT_CONST_STRING_CONST_STRING_SIZE, ATTR_PURE_NOTHROW_NONNULL_LEAF)
|
||||
DEF_LIB_BUILTIN (BUILT_IN_STRNCAT, "strncat", BT_FN_STRING_STRING_CONST_STRING_SIZE, ATTR_RET1_NOTHROW_NONNULL_LEAF)
|
||||
DEF_LIB_BUILTIN (BUILT_IN_STRNCAT, "strncat", BT_FN_STRING_STRING_CONST_STRING_SIZE, ATTR_NOTHROW_NONNULL_LEAF)
|
||||
DEF_LIB_BUILTIN (BUILT_IN_STRNCMP, "strncmp", BT_FN_INT_CONST_STRING_CONST_STRING_SIZE, ATTR_PURE_NOTHROW_NONNULL_LEAF)
|
||||
DEF_LIB_BUILTIN (BUILT_IN_STRNCPY, "strncpy", BT_FN_STRING_STRING_CONST_STRING_SIZE, ATTR_RET1_NOTHROW_NONNULL_LEAF)
|
||||
DEF_LIB_BUILTIN (BUILT_IN_STRNCPY, "strncpy", BT_FN_STRING_STRING_CONST_STRING_SIZE, ATTR_NOTHROW_NONNULL_LEAF)
|
||||
DEF_EXT_LIB_BUILTIN (BUILT_IN_STRNLEN, "strnlen", BT_FN_SIZE_CONST_STRING_SIZE, ATTR_PURE_NOTHROW_NONNULL_LEAF)
|
||||
DEF_LIB_BUILTIN (BUILT_IN_STRPBRK, "strpbrk", BT_FN_STRING_CONST_STRING_CONST_STRING, ATTR_PURE_NOTHROW_NONNULL_LEAF)
|
||||
DEF_LIB_BUILTIN (BUILT_IN_STRRCHR, "strrchr", BT_FN_STRING_CONST_STRING_INT, ATTR_PURE_NOTHROW_NONNULL_LEAF)
|
||||
|
@ -970,16 +970,16 @@ DEF_BUILTIN_STUB (BUILT_IN_STRNCMP_EQ, "__builtin_strncmp_eq")
|
|||
|
||||
/* Object size checking builtins. */
|
||||
DEF_GCC_BUILTIN (BUILT_IN_OBJECT_SIZE, "object_size", BT_FN_SIZE_CONST_PTR_INT, ATTR_CONST_NOTHROW_LEAF_LIST)
|
||||
DEF_EXT_LIB_BUILTIN (BUILT_IN_MEMCPY_CHK, "__memcpy_chk", BT_FN_PTR_PTR_CONST_PTR_SIZE_SIZE, ATTR_RET1_NOTHROW_NONNULL_LEAF)
|
||||
DEF_EXT_LIB_BUILTIN (BUILT_IN_MEMMOVE_CHK, "__memmove_chk", BT_FN_PTR_PTR_CONST_PTR_SIZE_SIZE, ATTR_RET1_NOTHROW_NONNULL_LEAF)
|
||||
DEF_EXT_LIB_BUILTIN (BUILT_IN_MEMCPY_CHK, "__memcpy_chk", BT_FN_PTR_PTR_CONST_PTR_SIZE_SIZE, ATTR_NOTHROW_NONNULL_LEAF)
|
||||
DEF_EXT_LIB_BUILTIN (BUILT_IN_MEMMOVE_CHK, "__memmove_chk", BT_FN_PTR_PTR_CONST_PTR_SIZE_SIZE, ATTR_NOTHROW_NONNULL_LEAF)
|
||||
DEF_EXT_LIB_BUILTIN (BUILT_IN_MEMPCPY_CHK, "__mempcpy_chk", BT_FN_PTR_PTR_CONST_PTR_SIZE_SIZE, ATTR_RETNONNULL_NOTHROW_LEAF)
|
||||
DEF_EXT_LIB_BUILTIN (BUILT_IN_MEMSET_CHK, "__memset_chk", BT_FN_PTR_PTR_INT_SIZE_SIZE, ATTR_RET1_NOTHROW_NONNULL_LEAF)
|
||||
DEF_EXT_LIB_BUILTIN (BUILT_IN_MEMSET_CHK, "__memset_chk", BT_FN_PTR_PTR_INT_SIZE_SIZE, ATTR_NOTHROW_NONNULL_LEAF)
|
||||
DEF_EXT_LIB_BUILTIN (BUILT_IN_STPCPY_CHK, "__stpcpy_chk", BT_FN_STRING_STRING_CONST_STRING_SIZE, ATTR_RETNONNULL_NOTHROW_LEAF)
|
||||
DEF_EXT_LIB_BUILTIN (BUILT_IN_STPNCPY_CHK, "__stpncpy_chk", BT_FN_STRING_STRING_CONST_STRING_SIZE_SIZE, ATTR_RETNONNULL_NOTHROW_LEAF)
|
||||
DEF_EXT_LIB_BUILTIN (BUILT_IN_STRCAT_CHK, "__strcat_chk", BT_FN_STRING_STRING_CONST_STRING_SIZE, ATTR_RET1_NOTHROW_NONNULL_LEAF)
|
||||
DEF_EXT_LIB_BUILTIN (BUILT_IN_STRCPY_CHK, "__strcpy_chk", BT_FN_STRING_STRING_CONST_STRING_SIZE, ATTR_RET1_NOTHROW_NONNULL_LEAF)
|
||||
DEF_EXT_LIB_BUILTIN (BUILT_IN_STRNCAT_CHK, "__strncat_chk", BT_FN_STRING_STRING_CONST_STRING_SIZE_SIZE, ATTR_RET1_NOTHROW_NONNULL_LEAF)
|
||||
DEF_EXT_LIB_BUILTIN (BUILT_IN_STRNCPY_CHK, "__strncpy_chk", BT_FN_STRING_STRING_CONST_STRING_SIZE_SIZE, ATTR_RET1_NOTHROW_NONNULL_LEAF)
|
||||
DEF_EXT_LIB_BUILTIN (BUILT_IN_STRCAT_CHK, "__strcat_chk", BT_FN_STRING_STRING_CONST_STRING_SIZE, ATTR_NOTHROW_NONNULL_LEAF)
|
||||
DEF_EXT_LIB_BUILTIN (BUILT_IN_STRCPY_CHK, "__strcpy_chk", BT_FN_STRING_STRING_CONST_STRING_SIZE, ATTR_NOTHROW_NONNULL_LEAF)
|
||||
DEF_EXT_LIB_BUILTIN (BUILT_IN_STRNCAT_CHK, "__strncat_chk", BT_FN_STRING_STRING_CONST_STRING_SIZE_SIZE, ATTR_NOTHROW_NONNULL_LEAF)
|
||||
DEF_EXT_LIB_BUILTIN (BUILT_IN_STRNCPY_CHK, "__strncpy_chk", BT_FN_STRING_STRING_CONST_STRING_SIZE_SIZE, ATTR_NOTHROW_NONNULL_LEAF)
|
||||
DEF_EXT_LIB_BUILTIN (BUILT_IN_SNPRINTF_CHK, "__snprintf_chk", BT_FN_INT_STRING_SIZE_INT_SIZE_CONST_STRING_VAR, ATTR_FORMAT_PRINTF_NOTHROW_5_6)
|
||||
DEF_EXT_LIB_BUILTIN (BUILT_IN_SPRINTF_CHK, "__sprintf_chk", BT_FN_INT_STRING_INT_SIZE_CONST_STRING_VAR, ATTR_NOTHROW_NONNULL_1_FORMAT_PRINTF_4_5)
|
||||
DEF_EXT_LIB_BUILTIN (BUILT_IN_VSNPRINTF_CHK, "__vsnprintf_chk", BT_FN_INT_STRING_SIZE_INT_SIZE_CONST_STRING_VALIST_ARG, ATTR_FORMAT_PRINTF_NOTHROW_5_0)
|
||||
|
|
31
gcc/calls.c
31
gcc/calls.c
|
@ -630,21 +630,32 @@ special_function_p (const_tree fndecl, int flags)
|
|||
return flags;
|
||||
}
|
||||
|
||||
/* Return fnspec for DECL. */
|
||||
|
||||
static attr_fnspec
|
||||
decl_fnspec (tree fndecl)
|
||||
{
|
||||
tree attr;
|
||||
tree type = TREE_TYPE (fndecl);
|
||||
if (type)
|
||||
{
|
||||
attr = lookup_attribute ("fn spec", TYPE_ATTRIBUTES (type));
|
||||
if (attr)
|
||||
{
|
||||
return TREE_VALUE (TREE_VALUE (attr));
|
||||
}
|
||||
}
|
||||
if (fndecl_built_in_p (fndecl, BUILT_IN_NORMAL))
|
||||
return builtin_fnspec (fndecl);
|
||||
return "";
|
||||
}
|
||||
|
||||
/* Similar to special_function_p; return a set of ERF_ flags for the
|
||||
function FNDECL. */
|
||||
static int
|
||||
decl_return_flags (tree fndecl)
|
||||
{
|
||||
tree attr;
|
||||
tree type = TREE_TYPE (fndecl);
|
||||
if (!type)
|
||||
return 0;
|
||||
|
||||
attr = lookup_attribute ("fn spec", TYPE_ATTRIBUTES (type));
|
||||
if (!attr)
|
||||
return 0;
|
||||
|
||||
attr_fnspec fnspec (TREE_VALUE (TREE_VALUE (attr)));
|
||||
attr_fnspec fnspec = decl_fnspec (fndecl);
|
||||
|
||||
unsigned int arg;
|
||||
if (fnspec.returns_arg (&arg))
|
||||
|
|
39
gcc/gimple.c
39
gcc/gimple.c
|
@ -1487,23 +1487,30 @@ gimple_call_flags (const gimple *stmt)
|
|||
|
||||
/* Return the "fn spec" string for call STMT. */
|
||||
|
||||
static const_tree
|
||||
attr_fnspec
|
||||
gimple_call_fnspec (const gcall *stmt)
|
||||
{
|
||||
tree type, attr;
|
||||
|
||||
if (gimple_call_internal_p (stmt))
|
||||
return internal_fn_fnspec (gimple_call_internal_fn (stmt));
|
||||
{
|
||||
const_tree spec = internal_fn_fnspec (gimple_call_internal_fn (stmt));
|
||||
if (spec)
|
||||
return spec;
|
||||
else
|
||||
return "";
|
||||
}
|
||||
|
||||
type = gimple_call_fntype (stmt);
|
||||
if (!type)
|
||||
return NULL_TREE;
|
||||
|
||||
attr = lookup_attribute ("fn spec", TYPE_ATTRIBUTES (type));
|
||||
if (!attr)
|
||||
return NULL_TREE;
|
||||
|
||||
return TREE_VALUE (TREE_VALUE (attr));
|
||||
if (type)
|
||||
{
|
||||
attr = lookup_attribute ("fn spec", TYPE_ATTRIBUTES (type));
|
||||
if (attr)
|
||||
return TREE_VALUE (TREE_VALUE (attr));
|
||||
}
|
||||
if (gimple_call_builtin_p (stmt, BUILT_IN_NORMAL))
|
||||
return builtin_fnspec (gimple_call_fndecl (stmt));
|
||||
return "";
|
||||
}
|
||||
|
||||
/* Detects argument flags for argument number ARG on call STMT. */
|
||||
|
@ -1511,13 +1518,12 @@ gimple_call_fnspec (const gcall *stmt)
|
|||
int
|
||||
gimple_call_arg_flags (const gcall *stmt, unsigned arg)
|
||||
{
|
||||
const_tree attr = gimple_call_fnspec (stmt);
|
||||
attr_fnspec fnspec = gimple_call_fnspec (stmt);
|
||||
|
||||
if (!attr)
|
||||
if (!fnspec.known_p ())
|
||||
return 0;
|
||||
|
||||
int flags = 0;
|
||||
attr_fnspec fnspec (attr);
|
||||
|
||||
if (!fnspec.arg_specified_p (arg))
|
||||
;
|
||||
|
@ -1540,15 +1546,10 @@ gimple_call_arg_flags (const gcall *stmt, unsigned arg)
|
|||
int
|
||||
gimple_call_return_flags (const gcall *stmt)
|
||||
{
|
||||
const_tree attr;
|
||||
|
||||
if (gimple_call_flags (stmt) & ECF_MALLOC)
|
||||
return ERF_NOALIAS;
|
||||
|
||||
attr = gimple_call_fnspec (stmt);
|
||||
if (!attr)
|
||||
return 0;
|
||||
attr_fnspec fnspec (attr);
|
||||
attr_fnspec fnspec = gimple_call_fnspec (stmt);
|
||||
|
||||
unsigned int arg_no;
|
||||
if (fnspec.returns_arg (&arg_no))
|
||||
|
|
|
@ -44,6 +44,7 @@ along with GCC; see the file COPYING3. If not see
|
|||
#include "errors.h"
|
||||
#include "dbgcnt.h"
|
||||
#include "gimple-pretty-print.h"
|
||||
#include "print-tree.h"
|
||||
|
||||
/* Broad overview of how alias analysis on gimple works:
|
||||
|
||||
|
@ -2572,6 +2573,99 @@ modref_may_conflict (const gimple *stmt,
|
|||
return false;
|
||||
}
|
||||
|
||||
/* Check if REF conflicts with call using "fn spec" attribute.
|
||||
If CLOBBER is true we are checking for writes, otherwise check loads.
|
||||
|
||||
Return 0 if there are no conflicts (except for possible function call
|
||||
argument reads), 1 if there are conflicts and -1 if we can not decide by
|
||||
fn spec. */
|
||||
|
||||
static int
|
||||
check_fnspec (gcall *call, ao_ref *ref, bool clobber)
|
||||
{
|
||||
attr_fnspec fnspec = gimple_call_fnspec (call);
|
||||
if (fnspec.known_p ())
|
||||
{
|
||||
if (clobber
|
||||
? !fnspec.global_memory_written_p ()
|
||||
: !fnspec.global_memory_read_p ())
|
||||
{
|
||||
for (unsigned int i = 0; i < gimple_call_num_args (call); i++)
|
||||
if (POINTER_TYPE_P (TREE_TYPE (gimple_call_arg (call, i)))
|
||||
&& (!fnspec.arg_specified_p (i)
|
||||
|| (clobber ? fnspec.arg_maybe_written_p (i)
|
||||
: fnspec.arg_maybe_read_p (i))))
|
||||
{
|
||||
ao_ref dref;
|
||||
tree size = NULL_TREE;
|
||||
unsigned int size_arg;
|
||||
|
||||
if (!fnspec.arg_specified_p (i))
|
||||
;
|
||||
else if (fnspec.arg_max_access_size_given_by_arg_p
|
||||
(i, &size_arg))
|
||||
size = gimple_call_arg (call, size_arg);
|
||||
else if (fnspec.arg_access_size_given_by_type_p (i))
|
||||
{
|
||||
tree callee = gimple_call_fndecl (call);
|
||||
tree t = TYPE_ARG_TYPES (TREE_TYPE (callee));
|
||||
|
||||
for (unsigned int p = 0; p < i; p++)
|
||||
t = TREE_CHAIN (t);
|
||||
size = TYPE_SIZE_UNIT (TREE_TYPE (TREE_VALUE (t)));
|
||||
}
|
||||
ao_ref_init_from_ptr_and_size (&dref,
|
||||
gimple_call_arg (call, i),
|
||||
size);
|
||||
if (refs_may_alias_p_1 (&dref, ref, false))
|
||||
return 1;
|
||||
}
|
||||
if (clobber
|
||||
&& fnspec.errno_maybe_written_p ()
|
||||
&& flag_errno_math
|
||||
&& targetm.ref_may_alias_errno (ref))
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* FIXME: we should handle barriers more consistently, but for now leave the
|
||||
check here. */
|
||||
if (gimple_call_builtin_p (call, BUILT_IN_NORMAL))
|
||||
switch (DECL_FUNCTION_CODE (gimple_call_fndecl (call)))
|
||||
{
|
||||
/* __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 1;
|
||||
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* If the call CALL may use the memory reference REF return true,
|
||||
otherwise return false. */
|
||||
|
||||
|
@ -2650,222 +2744,13 @@ ref_maybe_used_by_call_p_1 (gcall *call, ao_ref *ref, bool tbaa_p)
|
|||
&& !is_global_var (base))
|
||||
goto process_args;
|
||||
|
||||
/* 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. */
|
||||
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:
|
||||
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. */;
|
||||
}
|
||||
if (int res = check_fnspec (call, ref, false))
|
||||
{
|
||||
if (res == 1)
|
||||
return true;
|
||||
}
|
||||
else
|
||||
goto process_args;
|
||||
|
||||
/* Check if base is a global static variable that is not read
|
||||
by the function. */
|
||||
|
@ -3104,205 +2989,13 @@ 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;
|
||||
|
||||
/* 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. */
|
||||
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:
|
||||
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. */;
|
||||
}
|
||||
if (int res = check_fnspec (call, ref, true))
|
||||
{
|
||||
if (res == 1)
|
||||
return true;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
|
||||
/* Check if base is a global static variable that is not written
|
||||
by the function. */
|
||||
|
@ -4079,6 +3772,8 @@ void
|
|||
attr_fnspec::verify ()
|
||||
{
|
||||
bool err = false;
|
||||
if (!len)
|
||||
return;
|
||||
|
||||
/* Check return value specifier. */
|
||||
if (len < return_desc_size)
|
||||
|
@ -4092,8 +3787,17 @@ attr_fnspec::verify ()
|
|||
&& str[0] != 'R' && str[0] != 'W')
|
||||
err = true;
|
||||
|
||||
if (str[1] != ' ')
|
||||
err = true;
|
||||
switch (str[1])
|
||||
{
|
||||
case ' ':
|
||||
case 'p':
|
||||
case 'P':
|
||||
case 'c':
|
||||
case 'C':
|
||||
break;
|
||||
default:
|
||||
err = true;
|
||||
}
|
||||
|
||||
/* Now check all parameters. */
|
||||
for (unsigned int i = 0; arg_specified_p (i); i++)
|
||||
|
@ -4105,6 +3809,8 @@ attr_fnspec::verify ()
|
|||
case 'X':
|
||||
case 'r':
|
||||
case 'R':
|
||||
case 'o':
|
||||
case 'O':
|
||||
case 'w':
|
||||
case 'W':
|
||||
case '.':
|
||||
|
@ -4112,7 +3818,15 @@ attr_fnspec::verify ()
|
|||
default:
|
||||
err = true;
|
||||
}
|
||||
if (str[idx + 1] != ' ')
|
||||
if ((str[idx + 1] >= '1' && str[idx + 1] <= '9')
|
||||
|| str[idx + 1] == 't')
|
||||
{
|
||||
if (str[idx] != 'r' && str[idx] != 'R'
|
||||
&& str[idx] != 'w' && str[idx] != 'W'
|
||||
&& str[idx] != 'o' && str[idx] != 'O')
|
||||
err = true;
|
||||
}
|
||||
else if (str[idx + 1] != ' ')
|
||||
err = true;
|
||||
}
|
||||
if (err)
|
||||
|
|
Loading…
Add table
Reference in a new issue