diff options
author | rguenth <rguenth@138bc75d-0d04-0410-961f-82ee72b054a4> | 2010-05-10 09:43:17 +0000 |
---|---|---|
committer | rguenth <rguenth@138bc75d-0d04-0410-961f-82ee72b054a4> | 2010-05-10 09:43:17 +0000 |
commit | 8ce860079ffd104495b86756bd5c7729e69ff06f (patch) | |
tree | df80e1fff82251162890e6945cab6479837e953a | |
parent | 3912327b9151d79abcb95a324185c179f75d93ef (diff) | |
download | gcc-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/ChangeLog | 20 | ||||
-rw-r--r-- | gcc/c-common.c | 19 | ||||
-rw-r--r-- | gcc/fortran/ChangeLog | 10 | ||||
-rw-r--r-- | gcc/fortran/trans-decl.c | 58 | ||||
-rw-r--r-- | gcc/gimple.c | 74 | ||||
-rw-r--r-- | gcc/gimple.h | 2 | ||||
-rw-r--r-- | gcc/tree-ssa-alias.c | 4 | ||||
-rw-r--r-- | gcc/tree-ssa-structalias.c | 131 | ||||
-rw-r--r-- | gcc/tree.h | 24 |
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); |