aboutsummaryrefslogtreecommitdiff
path: root/gcc/ada/gcc-interface/utils.c
diff options
context:
space:
mode:
authorEric Botcazou <ebotcazou@adacore.com>2010-04-08 20:16:36 +0000
committerEric Botcazou <ebotcazou@gcc.gnu.org>2010-04-08 20:16:36 +0000
commitd47d0a8d97e00479a3efd3913bc996f319ac8139 (patch)
tree3bbe3665b3ad0f65e64b4973b9c1ddee13f15d9a /gcc/ada/gcc-interface/utils.c
parentdc5ee869f578f51a2691833b4d60054bf7e2a0a9 (diff)
downloadgcc-d47d0a8d97e00479a3efd3913bc996f319ac8139.zip
gcc-d47d0a8d97e00479a3efd3913bc996f319ac8139.tar.gz
gcc-d47d0a8d97e00479a3efd3913bc996f319ac8139.tar.bz2
tree.h (TREE_ADDRESSABLE): Document its effect for function types.
* tree.h (TREE_ADDRESSABLE): Document its effect for function types. * calls.c (expand_call): Pass the function type to aggregate_value_p. * function.c (aggregate_value_p): Do not honor DECL_BY_REFERENCE on the target function of a CALL_EXPR. Honor TREE_ADDRESSABLE on the function type instead. Reorder and simplify checks. * gimplify.c (gimplify_modify_expr_rhs) <WITH_SIZE_EXPR>: New case. ada/ * gcc-interface/ada-tree.h (TYPE_RETURNS_UNCONSTRAINED_P): Rename into. (TYPE_RETURN_UNCONSTRAINED_P): ...this. (TYPE_RETURNS_BY_REF_P): Rename into. (TYPE_RETURN_BY_DIRECT_REF_P): ...this. (TYPE_RETURNS_BY_TARGET_PTR_P): Delete. * gcc-interface/gigi.h (create_subprog_type): Adjust parameter names. (build_return_expr): Likewise. * gcc-interface/decl.c (gnat_to_gnu_entity) <E_Subprogram_Type>: Rename local variables. If the return Mechanism is By_Reference, pass return_by_invisible_ref_p to create_subprog_type instead of toggling TREE_ADDRESSABLE. Test return_by_invisible_ref_p in order to annotate the mechanism. Use regular return for contrained types with non-static size and return by invisible reference for unconstrained return types with default discriminants. Update comment. * gcc-interface/trans.c (Subprogram_Body_to_gnu): If the function returns by invisible reference, turn the RESULT_DECL into a pointer. Do not handle DECL_BY_REF_P in the CICO case here. (call_to_gnu): Remove code handling return by target pointer. For a function call, if the return type has non-constant size, generate the assignment with an INIT_EXPR. (gnat_to_gnu) <N_Return_Statement>: Remove dead code in the CICO case. If the function returns by invisible reference, build the copy return operation manually. (add_decl_expr): Initialize the variable with an INIT_EXPR. * gcc-interface/utils.c (create_subprog_type): Adjust parameter names. Adjust for renaming of macros. Copy the node only when necessary. (create_subprog_decl): Do not toggle TREE_ADDRESSABLE on the return type, only change DECL_BY_REFERENCE on the RETURN_DECL. (convert_from_reference): Delete. (is_byref_result): Likewise. (gnat_genericize_r): Likewise. (gnat_genericize): Likewise. (end_subprog_body): Do not call gnat_genericize. * gcc-interface/utils2.c (build_binary_op) <INIT_EXPR>: New case. (build_return_expr): Adjust parameter names, logic and comment. From-SVN: r158139
Diffstat (limited to 'gcc/ada/gcc-interface/utils.c')
-rw-r--r--gcc/ada/gcc-interface/utils.c255
1 files changed, 40 insertions, 215 deletions
diff --git a/gcc/ada/gcc-interface/utils.c b/gcc/ada/gcc-interface/utils.c
index ecb0495..412aa3a 100644
--- a/gcc/ada/gcc-interface/utils.c
+++ b/gcc/ada/gcc-interface/utils.c
@@ -1095,58 +1095,54 @@ split_plus (tree in, tree *pvar)
return bitsize_zero_node;
}
-/* Return a FUNCTION_TYPE node. RETURN_TYPE is the type returned by the
- subprogram. If it is void_type_node, then we are dealing with a procedure,
- otherwise we are dealing with a function. PARAM_DECL_LIST is a list of
- PARM_DECL nodes that are the subprogram arguments. CICO_LIST is the
- copy-in/copy-out list to be stored into TYPE_CICO_LIST.
- RETURNS_UNCONSTRAINED is true if the function returns an unconstrained
- object. RETURNS_BY_REF is true if the function returns by reference.
- RETURNS_BY_TARGET_PTR is true if the function is to be passed (as its
- first parameter) the address of the place to copy its result. */
+/* Return a FUNCTION_TYPE node. RETURN_TYPE is the type returned by the
+ subprogram. If it is VOID_TYPE, then we are dealing with a procedure,
+ otherwise we are dealing with a function. PARAM_DECL_LIST is a list of
+ PARM_DECL nodes that are the subprogram parameters. CICO_LIST is the
+ copy-in/copy-out list to be stored into the TYPE_CICO_LIST field.
+ RETURN_UNCONSTRAINED_P is true if the function returns an unconstrained
+ object. RETURN_BY_DIRECT_REF_P is true if the function returns by direct
+ reference. RETURN_BY_INVISI_REF_P is true if the function returns by
+ invisible reference. */
tree
create_subprog_type (tree return_type, tree param_decl_list, tree cico_list,
- bool returns_unconstrained, bool returns_by_ref,
- bool returns_by_target_ptr)
+ bool return_unconstrained_p, bool return_by_direct_ref_p,
+ bool return_by_invisi_ref_p)
{
/* A chain of TREE_LIST nodes whose TREE_VALUEs are the data type nodes of
- the subprogram formal parameters. This list is generated by traversing the
- input list of PARM_DECL nodes. */
- tree param_type_list = NULL;
- tree param_decl;
- tree type;
+ the subprogram formal parameters. This list is generated by traversing
+ the input list of PARM_DECL nodes. */
+ tree param_type_list = NULL_TREE;
+ tree t, type;
- for (param_decl = param_decl_list; param_decl;
- param_decl = TREE_CHAIN (param_decl))
- param_type_list = tree_cons (NULL_TREE, TREE_TYPE (param_decl),
- param_type_list);
+ for (t = param_decl_list; t; t = TREE_CHAIN (t))
+ param_type_list = tree_cons (NULL_TREE, TREE_TYPE (t), param_type_list);
/* The list of the function parameter types has to be terminated by the void
type to signal to the back-end that we are not dealing with a variable
- parameter subprogram, but that the subprogram has a fixed number of
- parameters. */
+ parameter subprogram, but that it has a fixed number of parameters. */
param_type_list = tree_cons (NULL_TREE, void_type_node, param_type_list);
- /* The list of argument types has been created in reverse
- so nreverse it. */
+ /* The list of argument types has been created in reverse so reverse it. */
param_type_list = nreverse (param_type_list);
type = build_function_type (return_type, param_type_list);
- /* TYPE may have been shared since GCC hashes types. If it has a CICO_LIST
- or the new type should, make a copy of TYPE. Likewise for
- RETURNS_UNCONSTRAINED and RETURNS_BY_REF. */
- if (TYPE_CI_CO_LIST (type) || cico_list
- || TYPE_RETURNS_UNCONSTRAINED_P (type) != returns_unconstrained
- || TYPE_RETURNS_BY_REF_P (type) != returns_by_ref
- || TYPE_RETURNS_BY_TARGET_PTR_P (type) != returns_by_target_ptr)
- type = copy_type (type);
+ /* TYPE may have been shared since GCC hashes types. If it has a different
+ CICO_LIST, make a copy. Likewise for the various flags. */
+ if (TYPE_CI_CO_LIST (type) != cico_list
+ || TYPE_RETURN_UNCONSTRAINED_P (type) != return_unconstrained_p
+ || TYPE_RETURN_BY_DIRECT_REF_P (type) != return_by_direct_ref_p
+ || TREE_ADDRESSABLE (type) != return_by_invisi_ref_p)
+ {
+ type = copy_type (type);
+ TYPE_CI_CO_LIST (type) = cico_list;
+ TYPE_RETURN_UNCONSTRAINED_P (type) = return_unconstrained_p;
+ TYPE_RETURN_BY_DIRECT_REF_P (type) = return_by_direct_ref_p;
+ TREE_ADDRESSABLE (type) = return_by_invisi_ref_p;
+ }
- TYPE_CI_CO_LIST (type) = cico_list;
- TYPE_RETURNS_UNCONSTRAINED_P (type) = returns_unconstrained;
- TYPE_RETURNS_BY_REF_P (type) = returns_by_ref;
- TYPE_RETURNS_BY_TARGET_PTR_P (type) = returns_by_target_ptr;
return type;
}
@@ -1828,9 +1824,10 @@ create_subprog_decl (tree subprog_name, tree asm_name,
bool public_flag, bool extern_flag,
struct attrib *attr_list, Node_Id gnat_node)
{
- tree return_type = TREE_TYPE (subprog_type);
- tree subprog_decl = build_decl (input_location,
- FUNCTION_DECL, subprog_name, subprog_type);
+ tree subprog_decl = build_decl (input_location, FUNCTION_DECL, subprog_name,
+ subprog_type);
+ tree result_decl = build_decl (input_location, RESULT_DECL, NULL_TREE,
+ TREE_TYPE (subprog_type));
/* If this is a non-inline function nested inside an inlined external
function, we cannot honor both requests without cloning the nested
@@ -1851,23 +1848,11 @@ create_subprog_decl (tree subprog_name, tree asm_name,
TREE_SIDE_EFFECTS (subprog_decl) = TYPE_VOLATILE (subprog_type);
DECL_DECLARED_INLINE_P (subprog_decl) = inline_flag;
DECL_ARGUMENTS (subprog_decl) = param_decl_list;
- DECL_RESULT (subprog_decl) = build_decl (input_location,
- RESULT_DECL, 0, return_type);
- DECL_ARTIFICIAL (DECL_RESULT (subprog_decl)) = 1;
- DECL_IGNORED_P (DECL_RESULT (subprog_decl)) = 1;
-
- /* TREE_ADDRESSABLE is set on the result type to request the use of the
- target by-reference return mechanism. This is not supported all the
- way down to RTL expansion with GCC 4, which ICEs on temporary creation
- attempts with such a type and expects DECL_BY_REFERENCE to be set on
- the RESULT_DECL instead - see gnat_genericize for more details. */
- if (TREE_ADDRESSABLE (TREE_TYPE (DECL_RESULT (subprog_decl))))
- {
- tree result_decl = DECL_RESULT (subprog_decl);
- TREE_ADDRESSABLE (TREE_TYPE (result_decl)) = 0;
- DECL_BY_REFERENCE (result_decl) = 1;
- }
+ DECL_ARTIFICIAL (result_decl) = 1;
+ DECL_IGNORED_P (result_decl) = 1;
+ DECL_BY_REFERENCE (result_decl) = TREE_ADDRESSABLE (subprog_type);
+ DECL_RESULT (subprog_decl) = result_decl;
if (asm_name)
{
@@ -1921,163 +1906,6 @@ begin_subprog_body (tree subprog_decl)
get_pending_sizes ();
}
-
-/* Helper for the genericization callback. Return a dereference of VAL
- if it is of a reference type. */
-
-static tree
-convert_from_reference (tree val)
-{
- tree value_type, ref;
-
- if (TREE_CODE (TREE_TYPE (val)) != REFERENCE_TYPE)
- return val;
-
- value_type = TREE_TYPE (TREE_TYPE (val));
- ref = build1 (INDIRECT_REF, value_type, val);
-
- /* See if what we reference is CONST or VOLATILE, which requires
- looking into array types to get to the component type. */
-
- while (TREE_CODE (value_type) == ARRAY_TYPE)
- value_type = TREE_TYPE (value_type);
-
- TREE_READONLY (ref)
- = (TYPE_QUALS (value_type) & TYPE_QUAL_CONST);
- TREE_THIS_VOLATILE (ref)
- = (TYPE_QUALS (value_type) & TYPE_QUAL_VOLATILE);
-
- TREE_SIDE_EFFECTS (ref)
- = (TREE_THIS_VOLATILE (ref) || TREE_SIDE_EFFECTS (val));
-
- return ref;
-}
-
-/* Helper for the genericization callback. Returns true if T denotes
- a RESULT_DECL with DECL_BY_REFERENCE set. */
-
-static inline bool
-is_byref_result (tree t)
-{
- return (TREE_CODE (t) == RESULT_DECL && DECL_BY_REFERENCE (t));
-}
-
-
-/* Tree walking callback for gnat_genericize. Currently ...
-
- o Adjust references to the function's DECL_RESULT if it is marked
- DECL_BY_REFERENCE and so has had its type turned into a reference
- type at the end of the function compilation. */
-
-static tree
-gnat_genericize_r (tree *stmt_p, int *walk_subtrees, void *data)
-{
- /* This implementation is modeled after what the C++ front-end is
- doing, basis of the downstream passes behavior. */
-
- tree stmt = *stmt_p;
- struct pointer_set_t *p_set = (struct pointer_set_t*) data;
-
- /* If we have a direct mention of the result decl, dereference. */
- if (is_byref_result (stmt))
- {
- *stmt_p = convert_from_reference (stmt);
- *walk_subtrees = 0;
- return NULL;
- }
-
- /* Otherwise, no need to walk the same tree twice. */
- if (pointer_set_contains (p_set, stmt))
- {
- *walk_subtrees = 0;
- return NULL_TREE;
- }
-
- /* If we are taking the address of what now is a reference, just get the
- reference value. */
- if (TREE_CODE (stmt) == ADDR_EXPR
- && is_byref_result (TREE_OPERAND (stmt, 0)))
- {
- *stmt_p = convert (TREE_TYPE (stmt), TREE_OPERAND (stmt, 0));
- *walk_subtrees = 0;
- }
-
- /* Don't dereference an by-reference RESULT_DECL inside a RETURN_EXPR. */
- else if (TREE_CODE (stmt) == RETURN_EXPR
- && TREE_OPERAND (stmt, 0)
- && is_byref_result (TREE_OPERAND (stmt, 0)))
- *walk_subtrees = 0;
-
- /* Don't look inside trees that cannot embed references of interest. */
- else if (IS_TYPE_OR_DECL_P (stmt))
- *walk_subtrees = 0;
-
- pointer_set_insert (p_set, *stmt_p);
-
- return NULL;
-}
-
-/* Perform lowering of Ada trees to GENERIC. In particular:
-
- o Turn a DECL_BY_REFERENCE RESULT_DECL into a real by-reference decl
- and adjust all the references to this decl accordingly. */
-
-static void
-gnat_genericize (tree fndecl)
-{
- /* Prior to GCC 4, an explicit By_Reference result mechanism for a function
- was handled by simply setting TREE_ADDRESSABLE on the result type.
- Everything required to actually pass by invisible ref using the target
- mechanism (e.g. extra parameter) was handled at RTL expansion time.
-
- This doesn't work with GCC 4 any more for several reasons. First, the
- gimplification process might need the creation of temporaries of this
- type, and the gimplifier ICEs on such attempts. Second, the middle-end
- now relies on a different attribute for such cases (DECL_BY_REFERENCE on
- RESULT/PARM_DECLs), and expects the user invisible by-reference-ness to
- be explicitly accounted for by the front-end in the function body.
-
- We achieve the complete transformation in two steps:
-
- 1/ create_subprog_decl performs early attribute tweaks: it clears
- TREE_ADDRESSABLE from the result type and sets DECL_BY_REFERENCE on
- the result decl. The former ensures that the bit isn't set in the GCC
- tree saved for the function, so prevents ICEs on temporary creation.
- The latter we use here to trigger the rest of the processing.
-
- 2/ This function performs the type transformation on the result decl
- and adjusts all the references to this decl from the function body
- accordingly.
-
- Clearing TREE_ADDRESSABLE from the type differs from the C++ front-end
- strategy, which escapes the gimplifier temporary creation issues by
- creating it's own temporaries using TARGET_EXPR nodes. Our way relies
- on simple specific support code in aggregate_value_p to look at the
- target function result decl explicitly. */
-
- struct pointer_set_t *p_set;
- tree decl_result = DECL_RESULT (fndecl);
-
- if (!DECL_BY_REFERENCE (decl_result))
- return;
-
- /* Make the DECL_RESULT explicitly by-reference and adjust all the
- occurrences in the function body using the common tree-walking facility.
- We want to see every occurrence of the result decl to adjust the
- referencing tree, so need to use our own pointer set to control which
- trees should be visited again or not. */
-
- p_set = pointer_set_create ();
-
- TREE_TYPE (decl_result) = build_reference_type (TREE_TYPE (decl_result));
- TREE_ADDRESSABLE (decl_result) = 0;
- relayout_decl (decl_result);
-
- walk_tree (&DECL_SAVED_TREE (fndecl), gnat_genericize_r, p_set, NULL);
-
- pointer_set_destroy (p_set);
-}
-
/* Finish the definition of the current subprogram BODY and finalize it. */
void
@@ -2111,9 +1939,6 @@ end_subprog_body (tree body)
if (type_annotate_only)
return;
- /* Perform the required pre-gimplification transformations on the tree. */
- gnat_genericize (fndecl);
-
/* Dump functions before gimplification. */
dump_function (TDI_original, fndecl);