aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJan Hubicka <jh@suse.cz>2020-10-26 20:19:33 +0100
committerJan Hubicka <jh@suse.cz>2020-10-26 20:22:16 +0100
commit4f8cfb42883cc247f11096a3703e379d1f24ab3f (patch)
tree427a28a3f52d39bc54bd04eda144d76ae53e7765
parent2118438f49f0c193abe3fa3def350a8129045746 (diff)
downloadgcc-4f8cfb42883cc247f11096a3703e379d1f24ab3f.zip
gcc-4f8cfb42883cc247f11096a3703e379d1f24ab3f.tar.gz
gcc-4f8cfb42883cc247f11096a3703e379d1f24ab3f.tar.bz2
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.
-rw-r--r--gcc/attr-fnspec.h104
-rw-r--r--gcc/builtins.c163
-rw-r--r--gcc/builtins.def28
-rw-r--r--gcc/calls.c31
-rw-r--r--gcc/gimple.c39
-rw-r--r--gcc/tree-ssa-alias.c550
6 files changed, 452 insertions, 463 deletions
diff --git a/gcc/attr-fnspec.h b/gcc/attr-fnspec.h
index d38b84a..78b1a5a 100644
--- a/gcc/attr-fnspec.h
+++ b/gcc/attr-fnspec.h
@@ -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 */
diff --git a/gcc/builtins.c b/gcc/builtins.c
index 72627b5..e7d4ff3 100644
--- a/gcc/builtins.c
+++ b/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 "";
+ }
+}
diff --git a/gcc/builtins.def b/gcc/builtins.def
index 95428c0..61aff89 100644
--- a/gcc/builtins.def
+++ b/gcc/builtins.def
@@ -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)
diff --git a/gcc/calls.c b/gcc/calls.c
index 17b8e2f..a8f4596 100644
--- a/gcc/calls.c
+++ b/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))
diff --git a/gcc/gimple.c b/gcc/gimple.c
index f19e24d..469e6f3 100644
--- a/gcc/gimple.c
+++ b/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))
diff --git a/gcc/tree-ssa-alias.c b/gcc/tree-ssa-alias.c
index 877e499..bc0f32a 100644
--- a/gcc/tree-ssa-alias.c
+++ b/gcc/tree-ssa-alias.c
@@ -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)