summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorrguenth <rguenth@138bc75d-0d04-0410-961f-82ee72b054a4>2010-05-10 09:43:17 +0000
committerrguenth <rguenth@138bc75d-0d04-0410-961f-82ee72b054a4>2010-05-10 09:43:17 +0000
commit8ce860079ffd104495b86756bd5c7729e69ff06f (patch)
treedf80e1fff82251162890e6945cab6479837e953a
parent3912327b9151d79abcb95a324185c179f75d93ef (diff)
downloadgcc-8ce860079ffd104495b86756bd5c7729e69ff06f.tar.gz
2010-05-10 Richard Guenther <rguenther@suse.de>
* c-common.c (struct c_common_attributes): Add fnspec attribute. (handle_fnspec_attribute): New function. * gimple.h (gimple_call_return_flags): Declare. (gimple_call_arg_flags): Likewise. * gimple.c (gimple_call_arg_flags): New function. (gimple_call_return_flags): Likewise. * tree.h (EAF_DIRECT, EAF_NOCLOBBER, EAF_NOESCAPE, EAF_UNUSED): New argument flags. (ERF_RETURN_ARG_MASK, ERF_RETURNS_ARG, ERF_NOALIAS): New function return value flags. * tree-ssa-alias.c (ref_maybe_used_by_call_p_1): Skip unused args. * tree-ssa-structalias.c (make_constraint_from_heapvar): Split main work to ... (make_heapvar_for): ... this new function. (handle_rhs_call): Handle fnspec attribute argument specifiers. (handle_lhs_call): Likewise. (find_func_aliases): Adjust. fortran/ * trans-decl.c (gfc_build_library_function_decl): Split out worker to ... (build_library_function_decl_1): ... this new function. Set a fnspec attribute if a specification was provided. (gfc_build_library_function_decl_with_spec): New function. (gfc_build_intrinsic_function_decls): Annotate internal_pack and internal_unpack. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@159215 138bc75d-0d04-0410-961f-82ee72b054a4
-rw-r--r--gcc/ChangeLog20
-rw-r--r--gcc/c-common.c19
-rw-r--r--gcc/fortran/ChangeLog10
-rw-r--r--gcc/fortran/trans-decl.c58
-rw-r--r--gcc/gimple.c74
-rw-r--r--gcc/gimple.h2
-rw-r--r--gcc/tree-ssa-alias.c4
-rw-r--r--gcc/tree-ssa-structalias.c131
-rw-r--r--gcc/tree.h24
9 files changed, 301 insertions, 41 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 07c5dd790bd..e31c2f4bc41 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,5 +1,25 @@
2010-05-10 Richard Guenther <rguenther@suse.de>
+ * c-common.c (struct c_common_attributes): Add fnspec attribute.
+ (handle_fnspec_attribute): New function.
+ * gimple.h (gimple_call_return_flags): Declare.
+ (gimple_call_arg_flags): Likewise.
+ * gimple.c (gimple_call_arg_flags): New function.
+ (gimple_call_return_flags): Likewise.
+ * tree.h (EAF_DIRECT, EAF_NOCLOBBER, EAF_NOESCAPE, EAF_UNUSED):
+ New argument flags.
+ (ERF_RETURN_ARG_MASK, ERF_RETURNS_ARG, ERF_NOALIAS): New function
+ return value flags.
+ * tree-ssa-alias.c (ref_maybe_used_by_call_p_1): Skip unused args.
+ * tree-ssa-structalias.c (make_constraint_from_heapvar): Split
+ main work to ...
+ (make_heapvar_for): ... this new function.
+ (handle_rhs_call): Handle fnspec attribute argument specifiers.
+ (handle_lhs_call): Likewise.
+ (find_func_aliases): Adjust.
+
+2010-05-10 Richard Guenther <rguenther@suse.de>
+
PR tree-optimization/44050
* tree-inline.c (tree_function_versioning): Clone the ipa-pta
flag.
diff --git a/gcc/c-common.c b/gcc/c-common.c
index e11b6aff475..7dce96214ea 100644
--- a/gcc/c-common.c
+++ b/gcc/c-common.c
@@ -529,6 +529,7 @@ static tree handle_type_generic_attribute (tree *, tree, tree, int, bool *);
static tree handle_alloc_size_attribute (tree *, tree, tree, int, bool *);
static tree handle_target_attribute (tree *, tree, tree, int, bool *);
static tree handle_optimize_attribute (tree *, tree, tree, int, bool *);
+static tree handle_fnspec_attribute (tree *, tree, tree, int, bool *);
static void check_function_nonnull (tree, int, tree *);
static void check_nonnull_arg (void *, tree, unsigned HOST_WIDE_INT);
@@ -829,6 +830,10 @@ const struct attribute_spec c_common_attribute_table[] =
handle_target_attribute },
{ "optimize", 1, -1, true, false, false,
handle_optimize_attribute },
+ /* For internal use (marking of builtins and runtime functions) only.
+ The name contains space to prevent its usage in source code. */
+ { "fn spec", 1, 1, false, true, true,
+ handle_fnspec_attribute },
{ NULL, 0, 0, false, false, false, NULL }
};
@@ -7138,6 +7143,20 @@ handle_alloc_size_attribute (tree *node, tree ARG_UNUSED (name), tree args,
return NULL_TREE;
}
+/* Handle a "fn spec" attribute; arguments as in
+ struct attribute_spec.handler. */
+
+static tree
+handle_fnspec_attribute (tree *node ATTRIBUTE_UNUSED, tree ARG_UNUSED (name),
+ tree args, int ARG_UNUSED (flags),
+ bool *no_add_attrs ATTRIBUTE_UNUSED)
+{
+ gcc_assert (args
+ && TREE_CODE (TREE_VALUE (args)) == STRING_CST
+ && !TREE_CHAIN (args));
+ return NULL_TREE;
+}
+
/* Handle a "returns_twice" attribute; arguments as in
struct attribute_spec.handler. */
diff --git a/gcc/fortran/ChangeLog b/gcc/fortran/ChangeLog
index 97e002a1a19..2b488fc7ac0 100644
--- a/gcc/fortran/ChangeLog
+++ b/gcc/fortran/ChangeLog
@@ -1,3 +1,13 @@
+2010-05-10 Richard Guenther <rguenther@suse.de>
+
+ * trans-decl.c (gfc_build_library_function_decl): Split out
+ worker to ...
+ (build_library_function_decl_1): ... this new function.
+ Set a fnspec attribute if a specification was provided.
+ (gfc_build_library_function_decl_with_spec): New function.
+ (gfc_build_intrinsic_function_decls): Annotate internal_pack
+ and internal_unpack.
+
2010-05-07 Daniel Franke <franke.daniel@gmail.com>
PR fortran/40728
diff --git a/gcc/fortran/trans-decl.c b/gcc/fortran/trans-decl.c
index 2ad4e737259..64d87caa073 100644
--- a/gcc/fortran/trans-decl.c
+++ b/gcc/fortran/trans-decl.c
@@ -2317,22 +2317,19 @@ gfc_get_fake_result_decl (gfc_symbol * sym, int parent_flag)
/* Builds a function decl. The remaining parameters are the types of the
function arguments. Negative nargs indicates a varargs function. */
-tree
-gfc_build_library_function_decl (tree name, tree rettype, int nargs, ...)
+static tree
+build_library_function_decl_1 (tree name, const char *spec,
+ tree rettype, int nargs, va_list p)
{
tree arglist;
tree argtype;
tree fntype;
tree fndecl;
- va_list p;
int n;
/* Library functions must be declared with global scope. */
gcc_assert (current_function_decl == NULL_TREE);
- va_start (p, nargs);
-
-
/* Create a list of the argument types. */
for (arglist = NULL_TREE, n = abs (nargs); n > 0; n--)
{
@@ -2348,6 +2345,14 @@ gfc_build_library_function_decl (tree name, tree rettype, int nargs, ...)
/* Build the function type and decl. */
fntype = build_function_type (rettype, arglist);
+ if (spec)
+ {
+ tree attr_args = build_tree_list (NULL_TREE,
+ build_string (strlen (spec), spec));
+ tree attrs = tree_cons (get_identifier ("fn spec"),
+ attr_args, TYPE_ATTRIBUTES (fntype));
+ fntype = build_type_attribute_variant (fntype, attrs);
+ }
fndecl = build_decl (input_location,
FUNCTION_DECL, name, fntype);
@@ -2355,8 +2360,6 @@ gfc_build_library_function_decl (tree name, tree rettype, int nargs, ...)
DECL_EXTERNAL (fndecl) = 1;
TREE_PUBLIC (fndecl) = 1;
- va_end (p);
-
pushdecl (fndecl);
rest_of_decl_compilation (fndecl, 1, 0);
@@ -2364,6 +2367,37 @@ gfc_build_library_function_decl (tree name, tree rettype, int nargs, ...)
return fndecl;
}
+/* Builds a function decl. The remaining parameters are the types of the
+ function arguments. Negative nargs indicates a varargs function. */
+
+tree
+gfc_build_library_function_decl (tree name, tree rettype, int nargs, ...)
+{
+ tree ret;
+ va_list args;
+ va_start (args, nargs);
+ ret = build_library_function_decl_1 (name, NULL, rettype, nargs, args);
+ va_end (args);
+ return ret;
+}
+
+/* Builds a function decl. The remaining parameters are the types of the
+ function arguments. Negative nargs indicates a varargs function.
+ The SPEC parameter specifies the function argument and return type
+ specification according to the fnspec function type attribute. */
+
+static tree
+gfc_build_library_function_decl_with_spec (tree name, const char *spec,
+ tree rettype, int nargs, ...)
+{
+ tree ret;
+ va_list args;
+ va_start (args, nargs);
+ ret = build_library_function_decl_1 (name, spec, rettype, nargs, args);
+ va_end (args);
+ return ret;
+}
+
static void
gfc_build_intrinsic_function_decls (void)
{
@@ -2821,12 +2855,12 @@ gfc_build_builtin_function_decls (void)
gfc_build_library_function_decl (get_identifier (PREFIX("set_max_subrecord_length")),
void_type_node, 1, integer_type_node);
- gfor_fndecl_in_pack = gfc_build_library_function_decl (
- get_identifier (PREFIX("internal_pack")),
+ gfor_fndecl_in_pack = gfc_build_library_function_decl_with_spec (
+ get_identifier (PREFIX("internal_pack")), ".r",
pvoid_type_node, 1, pvoid_type_node);
- gfor_fndecl_in_unpack = gfc_build_library_function_decl (
- get_identifier (PREFIX("internal_unpack")),
+ gfor_fndecl_in_unpack = gfc_build_library_function_decl_with_spec (
+ get_identifier (PREFIX("internal_unpack")), ".wR",
void_type_node, 2, pvoid_type_node, pvoid_type_node);
gfor_fndecl_associated =
diff --git a/gcc/gimple.c b/gcc/gimple.c
index d9a613ad189..6f3ba6dfb3a 100644
--- a/gcc/gimple.c
+++ b/gcc/gimple.c
@@ -1756,6 +1756,80 @@ gimple_call_flags (const_gimple stmt)
return flags;
}
+/* Detects argument flags for argument number ARG on call STMT. */
+
+int
+gimple_call_arg_flags (const_gimple stmt, unsigned arg)
+{
+ tree type = TREE_TYPE (TREE_TYPE (gimple_call_fn (stmt)));
+ tree attr = lookup_attribute ("fn spec", TYPE_ATTRIBUTES (type));
+ if (!attr)
+ return 0;
+
+ attr = TREE_VALUE (TREE_VALUE (attr));
+ if (1 + arg >= (unsigned) TREE_STRING_LENGTH (attr))
+ return 0;
+
+ switch (TREE_STRING_POINTER (attr)[1 + arg])
+ {
+ case 'x':
+ case 'X':
+ return EAF_UNUSED;
+
+ case 'R':
+ return EAF_DIRECT | EAF_NOCLOBBER | EAF_NOESCAPE;
+
+ case 'r':
+ return EAF_NOCLOBBER | EAF_NOESCAPE;
+
+ case 'W':
+ return EAF_DIRECT | EAF_NOESCAPE;
+
+ case 'w':
+ return EAF_NOESCAPE;
+
+ case '.':
+ default:
+ return 0;
+ }
+}
+
+/* Detects return flags for the call STMT. */
+
+int
+gimple_call_return_flags (const_gimple stmt)
+{
+ tree type;
+ tree attr = NULL_TREE;
+
+ if (gimple_call_flags (stmt) & ECF_MALLOC)
+ return ERF_NOALIAS;
+
+ type = TREE_TYPE (TREE_TYPE (gimple_call_fn (stmt)));
+ attr = lookup_attribute ("fn spec", TYPE_ATTRIBUTES (type));
+ if (!attr)
+ return 0;
+
+ attr = TREE_VALUE (TREE_VALUE (attr));
+ if (TREE_STRING_LENGTH (attr) < 1)
+ return 0;
+
+ switch (TREE_STRING_POINTER (attr)[0])
+ {
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ return ERF_RETURNS_ARG | (TREE_STRING_POINTER (attr)[0] - '1');
+
+ case 'm':
+ return ERF_NOALIAS;
+
+ case '.':
+ default:
+ return 0;
+ }
+}
/* Return true if GS is a copy assignment. */
diff --git a/gcc/gimple.h b/gcc/gimple.h
index 3daaa9e3c40..4f1c4d40355 100644
--- a/gcc/gimple.h
+++ b/gcc/gimple.h
@@ -857,6 +857,8 @@ void gimple_seq_free (gimple_seq);
void gimple_seq_add_seq (gimple_seq *, gimple_seq);
gimple_seq gimple_seq_copy (gimple_seq);
int gimple_call_flags (const_gimple);
+int gimple_call_return_flags (const_gimple);
+int gimple_call_arg_flags (const_gimple, unsigned);
void gimple_call_reset_alias_info (gimple);
bool gimple_assign_copy_p (gimple);
bool gimple_assign_ssa_name_copy_p (gimple);
diff --git a/gcc/tree-ssa-alias.c b/gcc/tree-ssa-alias.c
index 67c669e8b4b..715c2f10f9a 100644
--- a/gcc/tree-ssa-alias.c
+++ b/gcc/tree-ssa-alias.c
@@ -1097,6 +1097,10 @@ process_args:
for (i = 0; i < gimple_call_num_args (call); ++i)
{
tree op = gimple_call_arg (call, i);
+ int flags = gimple_call_arg_flags (call, i);
+
+ if (flags & EAF_UNUSED)
+ continue;
if (TREE_CODE (op) == WITH_SIZE_EXPR)
op = TREE_OPERAND (op, 0);
diff --git a/gcc/tree-ssa-structalias.c b/gcc/tree-ssa-structalias.c
index 19aa5db5f34..a45c6d52c6b 100644
--- a/gcc/tree-ssa-structalias.c
+++ b/gcc/tree-ssa-structalias.c
@@ -3599,11 +3599,11 @@ make_transitive_closure_constraints (varinfo_t vi)
process_constraint (new_constraint (lhs, rhs));
}
-/* Create a new artificial heap variable with NAME and make a
- constraint from it to LHS. Return the created variable. */
+/* Create a new artificial heap variable with NAME.
+ Return the created variable. */
static varinfo_t
-make_constraint_from_heapvar (varinfo_t lhs, const char *name)
+make_heapvar_for (varinfo_t lhs, const char *name)
{
varinfo_t vi;
tree heapvar = heapvar_lookup (lhs->decl, lhs->offset);
@@ -3635,6 +3635,16 @@ make_constraint_from_heapvar (varinfo_t lhs, const char *name)
vi->is_full_var = true;
insert_vi_for_tree (heapvar, vi);
+ return vi;
+}
+
+/* Create a new artificial heap variable with NAME and make a
+ constraint from it to LHS. Return the created variable. */
+
+static varinfo_t
+make_constraint_from_heapvar (varinfo_t lhs, const char *name)
+{
+ varinfo_t vi = make_heapvar_for (lhs, name);
make_constraint_from (lhs, vi->id);
return vi;
@@ -3709,17 +3719,61 @@ handle_rhs_call (gimple stmt, VEC(ce_s, heap) **results)
{
struct constraint_expr rhsc;
unsigned i;
+ bool returns_uses = false;
for (i = 0; i < gimple_call_num_args (stmt); ++i)
{
tree arg = gimple_call_arg (stmt, i);
+ int flags = gimple_call_arg_flags (stmt, i);
- /* Find those pointers being passed, and make sure they end up
- pointing to anything. */
- if (could_have_pointers (arg))
+ /* If the argument is not used or it does not contain pointers
+ we can ignore it. */
+ if ((flags & EAF_UNUSED)
+ || !could_have_pointers (arg))
+ continue;
+
+ /* As we compute ESCAPED context-insensitive we do not gain
+ any precision with just EAF_NOCLOBBER but not EAF_NOESCAPE
+ set. The argument would still get clobbered through the
+ escape solution.
+ ??? We might get away with less (and more precise) constraints
+ if using a temporary for transitively closing things. */
+ if ((flags & EAF_NOCLOBBER)
+ && (flags & EAF_NOESCAPE))
+ {
+ varinfo_t uses = get_call_use_vi (stmt);
+ if (!(flags & EAF_DIRECT))
+ make_transitive_closure_constraints (uses);
+ make_constraint_to (uses->id, arg);
+ returns_uses = true;
+ }
+ else if (flags & EAF_NOESCAPE)
+ {
+ varinfo_t uses = get_call_use_vi (stmt);
+ varinfo_t clobbers = get_call_clobber_vi (stmt);
+ if (!(flags & EAF_DIRECT))
+ {
+ make_transitive_closure_constraints (uses);
+ make_transitive_closure_constraints (clobbers);
+ }
+ make_constraint_to (uses->id, arg);
+ make_constraint_to (clobbers->id, arg);
+ returns_uses = true;
+ }
+ else
make_escape_constraint (arg);
}
+ /* If we added to the calls uses solution make sure we account for
+ pointers to it to be returned. */
+ if (returns_uses)
+ {
+ rhsc.var = get_call_use_vi (stmt)->id;
+ rhsc.offset = 0;
+ rhsc.type = SCALAR;
+ VEC_safe_push (ce_s, heap, *results, &rhsc);
+ }
+
/* The static chain escapes as well. */
if (gimple_call_chain (stmt))
make_escape_constraint (gimple_call_chain (stmt));
@@ -3752,44 +3806,63 @@ handle_rhs_call (gimple stmt, VEC(ce_s, heap) **results)
the LHS point to global and escaped variables. */
static void
-handle_lhs_call (tree lhs, int flags, VEC(ce_s, heap) *rhsc, tree fndecl)
+handle_lhs_call (gimple stmt, tree lhs, int flags, VEC(ce_s, heap) *rhsc,
+ tree fndecl)
{
VEC(ce_s, heap) *lhsc = NULL;
get_constraint_for (lhs, &lhsc);
-
- if (flags & ECF_MALLOC)
+ /* If the store is to a global decl make sure to
+ add proper escape constraints. */
+ lhs = get_base_address (lhs);
+ if (lhs
+ && DECL_P (lhs)
+ && is_global_var (lhs))
+ {
+ struct constraint_expr tmpc;
+ tmpc.var = escaped_id;
+ tmpc.offset = 0;
+ tmpc.type = SCALAR;
+ VEC_safe_push (ce_s, heap, lhsc, &tmpc);
+ }
+
+ /* If the call returns an argument unmodified override the rhs
+ constraints. */
+ flags = gimple_call_return_flags (stmt);
+ if (flags & ERF_RETURNS_ARG
+ && (flags & ERF_RETURN_ARG_MASK) < gimple_call_num_args (stmt))
+ {
+ tree arg;
+ rhsc = NULL;
+ arg = gimple_call_arg (stmt, flags & ERF_RETURN_ARG_MASK);
+ get_constraint_for (arg, &rhsc);
+ process_all_all_constraints (lhsc, rhsc);
+ VEC_free (ce_s, heap, rhsc);
+ }
+ else if (flags & ERF_NOALIAS)
{
varinfo_t vi;
- vi = make_constraint_from_heapvar (get_vi_for_tree (lhs), "HEAP");
+ struct constraint_expr tmpc;
+ rhsc = NULL;
+ vi = make_heapvar_for (get_vi_for_tree (lhs), "HEAP");
/* We delay marking allocated storage global until we know if
it escapes. */
DECL_EXTERNAL (vi->decl) = 0;
vi->is_global_var = 0;
/* If this is not a real malloc call assume the memory was
- initialized and thus may point to global memory. All
+ initialized and thus may point to global memory. All
builtin functions with the malloc attribute behave in a sane way. */
if (!fndecl
|| DECL_BUILT_IN_CLASS (fndecl) != BUILT_IN_NORMAL)
make_constraint_from (vi, nonlocal_id);
+ tmpc.var = vi->id;
+ tmpc.offset = 0;
+ tmpc.type = ADDRESSOF;
+ VEC_safe_push (ce_s, heap, rhsc, &tmpc);
}
- else if (VEC_length (ce_s, rhsc) > 0)
- {
- /* If the store is to a global decl make sure to
- add proper escape constraints. */
- lhs = get_base_address (lhs);
- if (lhs
- && DECL_P (lhs)
- && is_global_var (lhs))
- {
- struct constraint_expr tmpc;
- tmpc.var = escaped_id;
- tmpc.offset = 0;
- tmpc.type = SCALAR;
- VEC_safe_push (ce_s, heap, lhsc, &tmpc);
- }
- process_all_all_constraints (lhsc, rhsc);
- }
+
+ process_all_all_constraints (lhsc, rhsc);
+
VEC_free (ce_s, heap, lhsc);
}
@@ -4202,7 +4275,7 @@ find_func_aliases (gimple origt)
handle_rhs_call (t, &rhsc);
if (gimple_call_lhs (t)
&& could_have_pointers (gimple_call_lhs (t)))
- handle_lhs_call (gimple_call_lhs (t), flags, rhsc, fndecl);
+ handle_lhs_call (t, gimple_call_lhs (t), flags, rhsc, fndecl);
VEC_free (ce_s, heap, rhsc);
}
else
diff --git a/gcc/tree.h b/gcc/tree.h
index a03ede5781c..7eed68fc1b7 100644
--- a/gcc/tree.h
+++ b/gcc/tree.h
@@ -5169,6 +5169,30 @@ extern tree build_duplicate_type (tree);
extern int flags_from_decl_or_type (const_tree);
extern int call_expr_flags (const_tree);
+/* Call argument flags. */
+
+/* Nonzero if the argument is not dereferenced recursively, thus only
+ directly reachable memory is read or written. */
+#define EAF_DIRECT (1 << 0)
+/* Nonzero if memory reached by the argument is not clobbered. */
+#define EAF_NOCLOBBER (1 << 1)
+/* Nonzero if the argument does not escape. */
+#define EAF_NOESCAPE (1 << 2)
+/* Nonzero if the argument is not used by the function. */
+#define EAF_UNUSED (1 << 3)
+
+/* Call return flags. */
+
+/* Mask for the argument number that is returned. Lower two bits of
+ the return flags, encodes argument slots zero to three. */
+#define ERF_RETURN_ARG_MASK (3)
+/* Nonzero if the return value is equal to the argument number
+ flags & ERF_RETURN_ARG_MASK. */
+#define ERF_RETURNS_ARG (1 << 2)
+/* Nonzero if the return value does not alias with anything. Functions
+ with the malloc attribute have this set on their return value. */
+#define ERF_NOALIAS (1 << 3)
+
extern int setjmp_call_p (const_tree);
extern bool gimple_alloca_call_p (const_gimple);
extern bool alloca_call_p (const_tree);