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:
Jan Hubicka 2020-10-26 20:19:33 +01:00
parent 2118438f49
commit 4f8cfb4288
6 changed files with 452 additions and 463 deletions

View file

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

View file

@ -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 "";
}
}

View file

@ -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)

View file

@ -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))

View file

@ -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))

View file

@ -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)