aboutsummaryrefslogtreecommitdiff
path: root/gcc/tree-nested.c
diff options
context:
space:
mode:
authorEric Botcazou <ebotcazou@adacore.com>2016-10-16 20:13:32 +0000
committerEric Botcazou <ebotcazou@gcc.gnu.org>2016-10-16 20:13:32 +0000
commit4c640e26064224e29e2a88bd08cff338889da13c (patch)
tree4b953aabbc75af0eb299014b434f26373a999694 /gcc/tree-nested.c
parent855db69891d4f2a61a16f219d78daf8cd56e3058 (diff)
downloadgcc-4c640e26064224e29e2a88bd08cff338889da13c.zip
gcc-4c640e26064224e29e2a88bd08cff338889da13c.tar.gz
gcc-4c640e26064224e29e2a88bd08cff338889da13c.tar.bz2
re PR ada/37139 (DEP prevents using Ada tasking)
PR ada/37139 PR ada/67205 * common.opt (-ftrampolines): New option. * doc/invoke.texi (Code Gen Options): Document it. * doc/tm.texi.in (Trampolines): Add TARGET_CUSTOM_FUNCTION_DESCRIPTORS. * doc/tm.texi: Regenerate. * builtins.def: Add init_descriptor and adjust_descriptor. * builtins.c (expand_builtin_init_trampoline): Do not issue a warning on platforms with descriptors. (expand_builtin_init_descriptor): New function. (expand_builtin_adjust_descriptor): Likewise. (expand_builtin) <BUILT_IN_INIT_DESCRIPTOR>: New case. <BUILT_IN_ADJUST_DESCRIPTOR>: Likewise. * calls.c (prepare_call_address): Remove SIBCALLP parameter and add FLAGS parameter. Deal with indirect calls by descriptor and adjust. Set STATIC_CHAIN_REG_P on the static chain register, if any. (call_expr_flags): Set ECF_BY_DESCRIPTOR for calls by descriptor. (expand_call): Likewise. Move around call to prepare_call_address and pass all flags to it. * cfgexpand.c (expand_call_stmt): Reinstate CALL_EXPR_BY_DESCRIPTOR. * gimple.h (enum gf_mask): New GF_CALL_BY_DESCRIPTOR value. (gimple_call_set_by_descriptor): New setter. (gimple_call_by_descriptor_p): New getter. * gimple.c (gimple_build_call_from_tree): SetCALL_EXPR_BY_DESCRIPTOR. (gimple_call_flags): Deal with GF_CALL_BY_DESCRIPTOR. * langhooks.h (struct lang_hooks): Add custom_function_descriptors. * langhooks-def.h (LANG_HOOKS_CUSTOM_FUNCTION_DESCRIPTORS): Define. (LANG_HOOKS_INITIALIZER): Add LANG_HOOKS_CUSTOM_FUNCTION_DESCRIPTORS. * rtl.h (STATIC_CHAIN_REG_P): New macro. * rtlanal.c (find_first_parameter_load): Skip static chain registers. * target.def (custom_function_descriptors): New POD hook. * tree.h (FUNC_ADDR_BY_DESCRIPTOR): New flag on ADDR_EXPR. (CALL_EXPR_BY_DESCRIPTOR): New flag on CALL_EXPR. * tree-core.h (ECF_BY_DESCRIPTOR): New mask. Document FUNC_ADDR_BY_DESCRIPTOR and CALL_EXPR_BY_DESCRIPTOR. * tree.c (make_node_stat) <tcc_declaration>: Use FUNCTION_ALIGNMENT. (build_common_builtin_nodes): Initialize init_descriptor and adjust_descriptor. * tree-nested.c: Include target.h. (struct nesting_info): Add 'any_descr_created' field. (get_descriptor_type): New function. (lookup_element_for_decl): New function extracted from... (create_field_for_decl): Likewise. (lookup_tramp_for_decl): ...here. Adjust. (lookup_descr_for_decl): New function. (convert_tramp_reference_op): Deal with descriptors. (build_init_call_stmt): New function extracted from... (finalize_nesting_tree_1): ...here. Adjust and deal withdescriptors. * defaults.h (FUNCTION_ALIGNMENT): Define. (TRAMPOLINE_ALIGNMENT): Set to above instead of FUNCTION_BOUNDARY. * config/i386/i386.h (TARGET_CUSTOM_FUNCTION_DESCRIPTORS): Define. * config/ia64/ia64.h (TARGET_CUSTOM_FUNCTION_DESCRIPTORS): Likewise. * config/rs6000/rs6000.h (TARGET_CUSTOM_FUNCTION_DESCRIPTORS):Likewise. * config/sparc/sparc.h (TARGET_CUSTOM_FUNCTION_DESCRIPTORS): Likewise. ada/ * gcc-interface/misc.c (LANG_HOOKS_CUSTOM_FUNCTION_DESCRIPTORS):Define. * gcc-interface/trans.c (Attribute_to_gnu) <Attr_Access>: Deal with a zero TARGET_CUSTOM_FUNCTION_DESCRIPTORS specially for Code_Address. Otherwise, if TARGET_CUSTOM_FUNCTION_DESCRIPTORS is positive, set FUNC_ADDR_BY_DESCRIPTOR for 'Access/'Unrestricted_Access of nested subprograms if the type can use an internal representation. (call_to_gnu): Likewise, but set CALL_EXPR_BY_DESCRIPTOR on indirect calls if the type can use an internal representation. From-SVN: r241222
Diffstat (limited to 'gcc/tree-nested.c')
-rw-r--r--gcc/tree-nested.c169
1 files changed, 146 insertions, 23 deletions
diff --git a/gcc/tree-nested.c b/gcc/tree-nested.c
index 3aab8e1..36b120c 100644
--- a/gcc/tree-nested.c
+++ b/gcc/tree-nested.c
@@ -21,6 +21,7 @@
#include "system.h"
#include "coretypes.h"
#include "backend.h"
+#include "target.h"
#include "rtl.h"
#include "tree.h"
#include "gimple.h"
@@ -104,6 +105,7 @@ struct nesting_info
bool any_parm_remapped;
bool any_tramp_created;
+ bool any_descr_created;
char static_chain_added;
};
@@ -487,12 +489,38 @@ get_trampoline_type (struct nesting_info *info)
return trampoline_type;
}
-/* Given DECL, a nested function, find or create a field in the non-local
- frame structure for a trampoline for this function. */
+/* Build or return the type used to represent a nested function descriptor. */
+
+static GTY(()) tree descriptor_type;
static tree
-lookup_tramp_for_decl (struct nesting_info *info, tree decl,
- enum insert_option insert)
+get_descriptor_type (struct nesting_info *info)
+{
+ tree t;
+
+ if (descriptor_type)
+ return descriptor_type;
+
+ t = build_index_type (integer_one_node);
+ t = build_array_type (ptr_type_node, t);
+ t = build_decl (DECL_SOURCE_LOCATION (info->context),
+ FIELD_DECL, get_identifier ("__data"), t);
+
+ descriptor_type = make_node (RECORD_TYPE);
+ TYPE_NAME (descriptor_type) = get_identifier ("__builtin_descriptor");
+ TYPE_FIELDS (descriptor_type) = t;
+ layout_type (descriptor_type);
+ DECL_CONTEXT (t) = descriptor_type;
+
+ return descriptor_type;
+}
+
+/* Given DECL, a nested function, find or create an element in the
+ var map for this function. */
+
+static tree
+lookup_element_for_decl (struct nesting_info *info, tree decl,
+ enum insert_option insert)
{
if (insert == NO_INSERT)
{
@@ -502,19 +530,73 @@ lookup_tramp_for_decl (struct nesting_info *info, tree decl,
tree *slot = &info->var_map->get_or_insert (decl);
if (!*slot)
- {
- tree field = make_node (FIELD_DECL);
- DECL_NAME (field) = DECL_NAME (decl);
- TREE_TYPE (field) = get_trampoline_type (info);
- TREE_ADDRESSABLE (field) = 1;
+ *slot = build_tree_list (NULL_TREE, NULL_TREE);
- insert_field_into_struct (get_frame_type (info), field);
- *slot = field;
+ return (tree) *slot;
+}
+
+/* Given DECL, a nested function, create a field in the non-local
+ frame structure for this function. */
+
+static tree
+create_field_for_decl (struct nesting_info *info, tree decl, tree type)
+{
+ tree field = make_node (FIELD_DECL);
+ DECL_NAME (field) = DECL_NAME (decl);
+ TREE_TYPE (field) = type;
+ TREE_ADDRESSABLE (field) = 1;
+ insert_field_into_struct (get_frame_type (info), field);
+ return field;
+}
+
+/* Given DECL, a nested function, find or create a field in the non-local
+ frame structure for a trampoline for this function. */
+
+static tree
+lookup_tramp_for_decl (struct nesting_info *info, tree decl,
+ enum insert_option insert)
+{
+ tree elt, field;
+
+ elt = lookup_element_for_decl (info, decl, insert);
+ if (!elt)
+ return NULL_TREE;
+ field = TREE_PURPOSE (elt);
+
+ if (!field && insert == INSERT)
+ {
+ field = create_field_for_decl (info, decl, get_trampoline_type (info));
+ TREE_PURPOSE (elt) = field;
info->any_tramp_created = true;
}
- return *slot;
+ return field;
+}
+
+/* Given DECL, a nested function, find or create a field in the non-local
+ frame structure for a descriptor for this function. */
+
+static tree
+lookup_descr_for_decl (struct nesting_info *info, tree decl,
+ enum insert_option insert)
+{
+ tree elt, field;
+
+ elt = lookup_element_for_decl (info, decl, insert);
+ if (!elt)
+ return NULL_TREE;
+
+ field = TREE_VALUE (elt);
+
+ if (!field && insert == INSERT)
+ {
+ field = create_field_for_decl (info, decl, get_descriptor_type (info));
+ TREE_VALUE (elt) = field;
+ info->any_descr_created = true;
+ }
+
+ return field;
}
/* Build or return the field within the non-local frame state that holds
@@ -2304,6 +2386,7 @@ convert_tramp_reference_op (tree *tp, int *walk_subtrees, void *data)
struct walk_stmt_info *wi = (struct walk_stmt_info *) data;
struct nesting_info *const info = (struct nesting_info *) wi->info, *i;
tree t = *tp, decl, target_context, x, builtin;
+ bool descr;
gcall *call;
*walk_subtrees = 0;
@@ -2338,7 +2421,14 @@ convert_tramp_reference_op (tree *tp, int *walk_subtrees, void *data)
we need to insert the trampoline. */
for (i = info; i->context != target_context; i = i->outer)
continue;
- x = lookup_tramp_for_decl (i, decl, INSERT);
+
+ /* Decide whether to generate a descriptor or a trampoline. */
+ descr = FUNC_ADDR_BY_DESCRIPTOR (t) && !flag_trampolines;
+
+ if (descr)
+ x = lookup_descr_for_decl (i, decl, INSERT);
+ else
+ x = lookup_tramp_for_decl (i, decl, INSERT);
/* Compute the address of the field holding the trampoline. */
x = get_frame_field (info, target_context, x, &wi->gsi);
@@ -2347,7 +2437,10 @@ convert_tramp_reference_op (tree *tp, int *walk_subtrees, void *data)
/* Do machine-specific ugliness. Normally this will involve
computing extra alignment, but it can really be anything. */
- builtin = builtin_decl_implicit (BUILT_IN_ADJUST_TRAMPOLINE);
+ if (descr)
+ builtin = builtin_decl_implicit (BUILT_IN_ADJUST_DESCRIPTOR);
+ else
+ builtin = builtin_decl_implicit (BUILT_IN_ADJUST_TRAMPOLINE);
call = gimple_build_call (builtin, 1, x);
x = init_tmp_var_with_call (info, &wi->gsi, call);
@@ -2821,6 +2914,27 @@ fold_mem_refs (tree *const &e, void *data ATTRIBUTE_UNUSED)
return true;
}
+/* Given DECL, a nested function, build an initialization call for FIELD,
+ the trampoline or descriptor for DECL, using FUNC as the function. */
+
+static gcall *
+build_init_call_stmt (struct nesting_info *info, tree decl, tree field,
+ tree func)
+{
+ tree arg1, arg2, arg3, x;
+
+ gcc_assert (DECL_STATIC_CHAIN (decl));
+ arg3 = build_addr (info->frame_decl);
+
+ arg2 = build_addr (decl);
+
+ x = build3 (COMPONENT_REF, TREE_TYPE (field),
+ info->frame_decl, field, NULL_TREE);
+ arg1 = build_addr (x);
+
+ return gimple_build_call (func, 3, arg1, arg2, arg3);
+}
+
/* Do "everything else" to clean up or complete state collected by the various
walking passes -- create a field to hold the frame base address, lay out the
types and decls, generate code to initialize the frame decl, store critical
@@ -2966,23 +3080,32 @@ finalize_nesting_tree_1 (struct nesting_info *root)
struct nesting_info *i;
for (i = root->inner; i ; i = i->next)
{
- tree arg1, arg2, arg3, x, field;
+ tree field, x;
field = lookup_tramp_for_decl (root, i->context, NO_INSERT);
if (!field)
continue;
- gcc_assert (DECL_STATIC_CHAIN (i->context));
- arg3 = build_addr (root->frame_decl);
+ x = builtin_decl_implicit (BUILT_IN_INIT_TRAMPOLINE);
+ stmt = build_init_call_stmt (root, i->context, field, x);
+ gimple_seq_add_stmt (&stmt_list, stmt);
+ }
+ }
- arg2 = build_addr (i->context);
+ /* If descriptors were created, then we need to initialize them. */
+ if (root->any_descr_created)
+ {
+ struct nesting_info *i;
+ for (i = root->inner; i ; i = i->next)
+ {
+ tree field, x;
- x = build3 (COMPONENT_REF, TREE_TYPE (field),
- root->frame_decl, field, NULL_TREE);
- arg1 = build_addr (x);
+ field = lookup_descr_for_decl (root, i->context, NO_INSERT);
+ if (!field)
+ continue;
- x = builtin_decl_implicit (BUILT_IN_INIT_TRAMPOLINE);
- stmt = gimple_build_call (x, 3, arg1, arg2, arg3);
+ x = builtin_decl_implicit (BUILT_IN_INIT_DESCRIPTOR);
+ stmt = build_init_call_stmt (root, i->context, field, x);
gimple_seq_add_stmt (&stmt_list, stmt);
}
}