Commit d47d0a8d by Eric Botcazou Committed by Eric Botcazou

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
parent dc5ee869
2010-04-08 Eric Botcazou <ebotcazou@adacore.com>
* 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.
2010-04-08 Jing Yu <jingyu@google.com> 2010-04-08 Jing Yu <jingyu@google.com>
Zdenek Dvorak <ook@ucw.cz> Zdenek Dvorak <ook@ucw.cz>
......
2010-04-08 Eric Botcazou <ebotcazou@adacore.com>
* 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.
2010-04-07 Eric Botcazou <ebotcazou@adacore.com> 2010-04-07 Eric Botcazou <ebotcazou@adacore.com>
* exp_pakd.adb (Create_Packed_Array_Type): Always use a modular type * exp_pakd.adb (Create_Packed_Array_Type): Always use a modular type
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
* * * *
* C Header File * * C Header File *
* * * *
* Copyright (C) 1992-2009, Free Software Foundation, Inc. * * Copyright (C) 1992-2010, Free Software Foundation, Inc. *
* * * *
* GNAT is free software; you can redistribute it and/or modify it under * * GNAT is free software; you can redistribute it and/or modify it under *
* terms of the GNU General Public License as published by the Free Soft- * * terms of the GNU General Public License as published by the Free Soft- *
...@@ -90,7 +90,7 @@ do { \ ...@@ -90,7 +90,7 @@ do { \
/* For FUNCTION_TYPE, nonzero if this denotes a function returning an /* For FUNCTION_TYPE, nonzero if this denotes a function returning an
unconstrained array or record. */ unconstrained array or record. */
#define TYPE_RETURNS_UNCONSTRAINED_P(NODE) \ #define TYPE_RETURN_UNCONSTRAINED_P(NODE) \
TYPE_LANG_FLAG_1 (FUNCTION_TYPE_CHECK (NODE)) TYPE_LANG_FLAG_1 (FUNCTION_TYPE_CHECK (NODE))
/* For RECORD_TYPE, UNION_TYPE, and QUAL_UNION_TYPE, nonzero if this denotes /* For RECORD_TYPE, UNION_TYPE, and QUAL_UNION_TYPE, nonzero if this denotes
...@@ -135,8 +135,10 @@ do { \ ...@@ -135,8 +135,10 @@ do { \
#define TYPE_CONVENTION_FORTRAN_P(NODE) \ #define TYPE_CONVENTION_FORTRAN_P(NODE) \
TYPE_LANG_FLAG_4 (ARRAY_TYPE_CHECK (NODE)) TYPE_LANG_FLAG_4 (ARRAY_TYPE_CHECK (NODE))
/* For FUNCTION_TYPEs, nonzero if the function returns by reference. */ /* For FUNCTION_TYPEs, nonzero if the function returns by direct reference,
#define TYPE_RETURNS_BY_REF_P(NODE) \ i.e. the callee returns a pointer to a memory location it has allocated
and the caller only needs to dereference the pointer. */
#define TYPE_RETURN_BY_DIRECT_REF_P(NODE) \
TYPE_LANG_FLAG_4 (FUNCTION_TYPE_CHECK (NODE)) TYPE_LANG_FLAG_4 (FUNCTION_TYPE_CHECK (NODE))
/* For VOID_TYPE, ENUMERAL_TYPE, UNION_TYPE, and RECORD_TYPE, nonzero if this /* For VOID_TYPE, ENUMERAL_TYPE, UNION_TYPE, and RECORD_TYPE, nonzero if this
...@@ -148,11 +150,6 @@ do { \ ...@@ -148,11 +150,6 @@ do { \
|| TREE_CODE (NODE) == UNION_TYPE || TREE_CODE (NODE) == ENUMERAL_TYPE) \ || TREE_CODE (NODE) == UNION_TYPE || TREE_CODE (NODE) == ENUMERAL_TYPE) \
&& TYPE_DUMMY_P (NODE)) && TYPE_DUMMY_P (NODE))
/* For FUNCTION_TYPEs, nonzero if function returns by being passed a pointer
to a place to store its result. */
#define TYPE_RETURNS_BY_TARGET_PTR_P(NODE) \
TYPE_LANG_FLAG_5 (FUNCTION_TYPE_CHECK (NODE))
/* For an INTEGER_TYPE, nonzero if TYPE_ACTUAL_BOUNDS is present. */ /* For an INTEGER_TYPE, nonzero if TYPE_ACTUAL_BOUNDS is present. */
#define TYPE_HAS_ACTUAL_BOUNDS_P(NODE) \ #define TYPE_HAS_ACTUAL_BOUNDS_P(NODE) \
TYPE_LANG_FLAG_5 (INTEGER_TYPE_CHECK (NODE)) TYPE_LANG_FLAG_5 (INTEGER_TYPE_CHECK (NODE))
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
* * * *
* C Implementation File * * C Implementation File *
* * * *
* Copyright (C) 1992-2009, Free Software Foundation, Inc. * * Copyright (C) 1992-2010, Free Software Foundation, Inc. *
* * * *
* GNAT is free software; you can redistribute it and/or modify it under * * GNAT is free software; you can redistribute it and/or modify it under *
* terms of the GNU General Public License as published by the Free Soft- * * terms of the GNU General Public License as published by the Free Soft- *
...@@ -3799,13 +3799,13 @@ gnat_to_gnu_entity (Entity_Id gnat_entity, tree gnu_expr, int definition) ...@@ -3799,13 +3799,13 @@ gnat_to_gnu_entity (Entity_Id gnat_entity, tree gnu_expr, int definition)
tree gnu_field_list = NULL_TREE; tree gnu_field_list = NULL_TREE;
/* Non-null for subprograms containing parameters passed by copy-in /* Non-null for subprograms containing parameters passed by copy-in
copy-out (Ada In Out or Out parameters not passed by reference), copy-out (Ada In Out or Out parameters not passed by reference),
in which case it is the list of nodes used to specify the values of in which case it is the list of nodes used to specify the values
the in out/out parameters that are returned as a record upon of the In Out/Out parameters that are returned as a record upon
procedure return. The TREE_PURPOSE of an element of this list is procedure return. The TREE_PURPOSE of an element of this list is
a field of the record and the TREE_VALUE is the PARM_DECL a field of the record and the TREE_VALUE is the PARM_DECL
corresponding to that field. This list will be saved in the corresponding to that field. This list will be saved in the
TYPE_CI_CO_LIST field of the FUNCTION_TYPE node we create. */ TYPE_CI_CO_LIST field of the FUNCTION_TYPE node we create. */
tree gnu_return_list = NULL_TREE; tree gnu_cico_list = NULL_TREE;
/* If an import pragma asks to map this subprogram to a GCC builtin, /* If an import pragma asks to map this subprogram to a GCC builtin,
this is the builtin DECL node. */ this is the builtin DECL node. */
tree gnu_builtin_decl = NULL_TREE; tree gnu_builtin_decl = NULL_TREE;
...@@ -3831,9 +3831,9 @@ gnat_to_gnu_entity (Entity_Id gnat_entity, tree gnu_expr, int definition) ...@@ -3831,9 +3831,9 @@ gnat_to_gnu_entity (Entity_Id gnat_entity, tree gnu_expr, int definition)
&& Is_Pure (gnat_entity)); && Is_Pure (gnat_entity));
bool volatile_flag = No_Return (gnat_entity); bool volatile_flag = No_Return (gnat_entity);
bool returns_by_ref = false; bool return_by_direct_ref_p = false;
bool returns_unconstrained = false; bool return_by_invisi_ref_p = false;
bool returns_by_target_ptr = false; bool return_unconstrained_p = false;
bool has_copy_in_out = false; bool has_copy_in_out = false;
bool has_stub = false; bool has_stub = false;
int parmnum; int parmnum;
...@@ -3885,37 +3885,39 @@ gnat_to_gnu_entity (Entity_Id gnat_entity, tree gnu_expr, int definition) ...@@ -3885,37 +3885,39 @@ gnat_to_gnu_entity (Entity_Id gnat_entity, tree gnu_expr, int definition)
if (kind == E_Function || kind == E_Subprogram_Type) if (kind == E_Function || kind == E_Subprogram_Type)
gnu_return_type = gnat_to_gnu_type (Etype (gnat_entity)); gnu_return_type = gnat_to_gnu_type (Etype (gnat_entity));
/* If this function returns by reference, make the actual /* If this function returns by reference, make the actual return
return type of this function the pointer and mark the decl. */ type of this function the pointer and mark the decl. */
if (Returns_By_Ref (gnat_entity)) if (Returns_By_Ref (gnat_entity))
{ {
returns_by_ref = true;
gnu_return_type = build_pointer_type (gnu_return_type); gnu_return_type = build_pointer_type (gnu_return_type);
return_by_direct_ref_p = true;
} }
/* If the Mechanism is By_Reference, ensure the return type uses /* If the Mechanism is By_Reference, ensure this function uses the
the machine's by-reference mechanism, which may not the same target's by-invisible-reference mechanism, which may not be the
as above (e.g., it might be by passing a fake parameter). */ same as above (e.g. it might be passing an extra parameter).
else if (kind == E_Function
&& Mechanism (gnat_entity) == By_Reference) Prior to GCC 4, this was handled by just setting TREE_ADDRESSABLE
{ on the result type. Everything required to pass by invisible
TREE_ADDRESSABLE (gnu_return_type) = 1; reference using the target's mechanism (e.g. an extra parameter)
was handled at RTL expansion time.
/* We expect this bit to be reset by gigi shortly, so can avoid a
type node copy here. This actually also prevents troubles with This doesn't work with GCC 4 any more for several reasons. First,
the generation of debug information for the function, because the gimplification process might need to create temporaries of this
we might have issued such info for this type already, and would type and the gimplifier ICEs on such attempts; that's why the flag
be attaching a distinct type node to the function if we made a is now set on the function type instead. Second, the middle-end
copy here. */ now also relies on a different attribute, DECL_BY_REFERENCE on the
} RESULT_DECL, and expects the by-invisible-reference-ness to be made
explicit in the function body. */
/* If we are supposed to return an unconstrained array, else if (kind == E_Function && Mechanism (gnat_entity) == By_Reference)
actually return a fat pointer and make a note of that. Return return_by_invisi_ref_p = true;
a pointer to an unconstrained record of variable size. */
/* If we are supposed to return an unconstrained array, actually return
a fat pointer and make a note of that. */
else if (TREE_CODE (gnu_return_type) == UNCONSTRAINED_ARRAY_TYPE) else if (TREE_CODE (gnu_return_type) == UNCONSTRAINED_ARRAY_TYPE)
{ {
gnu_return_type = TREE_TYPE (gnu_return_type); gnu_return_type = TREE_TYPE (gnu_return_type);
returns_unconstrained = true; return_unconstrained_p = true;
} }
/* If the type requires a transient scope, the result is allocated /* If the type requires a transient scope, the result is allocated
...@@ -3924,7 +3926,7 @@ gnat_to_gnu_entity (Entity_Id gnat_entity, tree gnu_expr, int definition) ...@@ -3924,7 +3926,7 @@ gnat_to_gnu_entity (Entity_Id gnat_entity, tree gnu_expr, int definition)
else if (Requires_Transient_Scope (Etype (gnat_entity))) else if (Requires_Transient_Scope (Etype (gnat_entity)))
{ {
gnu_return_type = build_pointer_type (gnu_return_type); gnu_return_type = build_pointer_type (gnu_return_type);
returns_unconstrained = true; return_unconstrained_p = true;
} }
/* If the type is a padded type and the underlying type would not /* If the type is a padded type and the underlying type would not
...@@ -3936,20 +3938,17 @@ gnat_to_gnu_entity (Entity_Id gnat_entity, tree gnu_expr, int definition) ...@@ -3936,20 +3938,17 @@ gnat_to_gnu_entity (Entity_Id gnat_entity, tree gnu_expr, int definition)
|| Has_Foreign_Convention (gnat_entity))) || Has_Foreign_Convention (gnat_entity)))
gnu_return_type = TREE_TYPE (TYPE_FIELDS (gnu_return_type)); gnu_return_type = TREE_TYPE (TYPE_FIELDS (gnu_return_type));
/* If the return type has a non-constant size, we convert the function /* If the return type is unconstrained, that means it must have a
into a procedure and its caller will pass a pointer to an object as maximum size. Use the padded type as the effective return type.
the first parameter when we call the function. This can happen for And ensure the function uses the target's by-invisible-reference
an unconstrained type with a maximum size or a constrained type with mechanism to avoid copying too much data when it returns. */
a size not known at compile time. */ if (CONTAINS_PLACEHOLDER_P (TYPE_SIZE (gnu_return_type)))
if (TYPE_SIZE_UNIT (gnu_return_type)
&& !TREE_CONSTANT (TYPE_SIZE_UNIT (gnu_return_type)))
{ {
returns_by_target_ptr = true; gnu_return_type
gnu_param_list = maybe_pad_type (gnu_return_type,
= create_param_decl (get_identifier ("TARGET"), max_size (TYPE_SIZE (gnu_return_type), true),
build_reference_type (gnu_return_type), 0, gnat_entity, false, false, false, true);
true); return_by_invisi_ref_p = true;
gnu_return_type = void_type_node;
} }
/* If the return type has a size that overflows, we cannot have /* If the return type has a size that overflows, we cannot have
...@@ -4091,8 +4090,8 @@ gnat_to_gnu_entity (Entity_Id gnat_entity, tree gnu_expr, int definition) ...@@ -4091,8 +4090,8 @@ gnat_to_gnu_entity (Entity_Id gnat_entity, tree gnu_expr, int definition)
&DECL_SOURCE_LOCATION (gnu_field)); &DECL_SOURCE_LOCATION (gnu_field));
TREE_CHAIN (gnu_field) = gnu_field_list; TREE_CHAIN (gnu_field) = gnu_field_list;
gnu_field_list = gnu_field; gnu_field_list = gnu_field;
gnu_return_list = tree_cons (gnu_field, gnu_param, gnu_cico_list
gnu_return_list); = tree_cons (gnu_field, gnu_param, gnu_cico_list);
} }
} }
...@@ -4105,8 +4104,8 @@ gnat_to_gnu_entity (Entity_Id gnat_entity, tree gnu_expr, int definition) ...@@ -4105,8 +4104,8 @@ gnat_to_gnu_entity (Entity_Id gnat_entity, tree gnu_expr, int definition)
/* If we have a CICO list but it has only one entry, we convert /* If we have a CICO list but it has only one entry, we convert
this function into a function that simply returns that one this function into a function that simply returns that one
object. */ object. */
if (list_length (gnu_return_list) == 1) if (list_length (gnu_cico_list) == 1)
gnu_return_type = TREE_TYPE (TREE_PURPOSE (gnu_return_list)); gnu_return_type = TREE_TYPE (TREE_PURPOSE (gnu_cico_list));
if (Has_Stdcall_Convention (gnat_entity)) if (Has_Stdcall_Convention (gnat_entity))
prepend_one_attribute_to prepend_one_attribute_to
...@@ -4131,22 +4130,25 @@ gnat_to_gnu_entity (Entity_Id gnat_entity, tree gnu_expr, int definition) ...@@ -4131,22 +4130,25 @@ gnat_to_gnu_entity (Entity_Id gnat_entity, tree gnu_expr, int definition)
gnu_param_list = nreverse (gnu_param_list); gnu_param_list = nreverse (gnu_param_list);
if (has_stub) if (has_stub)
gnu_stub_param_list = nreverse (gnu_stub_param_list); gnu_stub_param_list = nreverse (gnu_stub_param_list);
gnu_return_list = nreverse (gnu_return_list); gnu_cico_list = nreverse (gnu_cico_list);
if (Ekind (gnat_entity) == E_Function) if (Ekind (gnat_entity) == E_Function)
Set_Mechanism (gnat_entity, Set_Mechanism (gnat_entity, return_unconstrained_p
(returns_by_ref || returns_unconstrained || return_by_direct_ref_p
? By_Reference : By_Copy)); || return_by_invisi_ref_p
? By_Reference : By_Copy);
gnu_type gnu_type
= create_subprog_type (gnu_return_type, gnu_param_list, = create_subprog_type (gnu_return_type, gnu_param_list,
gnu_return_list, returns_unconstrained, gnu_cico_list, return_unconstrained_p,
returns_by_ref, returns_by_target_ptr); return_by_direct_ref_p,
return_by_invisi_ref_p);
if (has_stub) if (has_stub)
gnu_stub_type gnu_stub_type
= create_subprog_type (gnu_return_type, gnu_stub_param_list, = create_subprog_type (gnu_return_type, gnu_stub_param_list,
gnu_return_list, returns_unconstrained, gnu_cico_list, return_unconstrained_p,
returns_by_ref, returns_by_target_ptr); return_by_direct_ref_p,
return_by_invisi_ref_p);
/* A subprogram (something that doesn't return anything) shouldn't /* A subprogram (something that doesn't return anything) shouldn't
be considered const since there would be no reason for such a be considered const since there would be no reason for such a
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
* * * *
* C Header File * * C Header File *
* * * *
* Copyright (C) 1992-2009, Free Software Foundation, Inc. * * Copyright (C) 1992-2010, Free Software Foundation, Inc. *
* * * *
* GNAT is free software; you can redistribute it and/or modify it under * * GNAT is free software; you can redistribute it and/or modify it under *
* terms of the GNU General Public License as published by the Free Soft- * * terms of the GNU General Public License as published by the Free Soft- *
...@@ -545,19 +545,19 @@ extern void add_parallel_type (tree decl, tree parallel_type); ...@@ -545,19 +545,19 @@ extern void add_parallel_type (tree decl, tree parallel_type);
/* Return the parallel type associated to a type, if any. */ /* Return the parallel type associated to a type, if any. */
extern tree get_parallel_type (tree type); extern tree get_parallel_type (tree type);
/* Returns a FUNCTION_TYPE node. RETURN_TYPE is the type returned by the /* 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, 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 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 PARM_DECL nodes that are the subprogram parameters. CICO_LIST is the
copy-in/copy-out list to be stored into TYPE_CI_CO_LIST. copy-in/copy-out list to be stored into the TYPE_CICO_LIST field.
RETURNS_UNCONSTRAINED is true if the function returns an unconstrained RETURN_UNCONSTRAINED_P is true if the function returns an unconstrained
object. RETURNS_BY_REF is true if the function returns by reference. object. RETURN_BY_DIRECT_REF_P is true if the function returns by direct
RETURNS_BY_TARGET_PTR is true if the function is to be passed (as its reference. RETURN_BY_INVISI_REF_P is true if the function returns by
first parameter) the address of the place to copy its result. */ invisible reference. */
extern tree create_subprog_type (tree return_type, tree param_decl_list, extern tree create_subprog_type (tree return_type, tree param_decl_list,
tree cico_list, bool returns_unconstrained, tree cico_list, bool return_unconstrained_p,
bool returns_by_ref, bool return_by_direct_ref_p,
bool returns_by_target_ptr); bool return_by_invisi_ref_p);
/* Return a copy of TYPE, but safe to modify in any way. */ /* Return a copy of TYPE, but safe to modify in any way. */
extern tree copy_type (tree type); extern tree copy_type (tree type);
...@@ -804,7 +804,7 @@ extern tree build_cond_expr (tree result_type, tree condition_operand, ...@@ -804,7 +804,7 @@ extern tree build_cond_expr (tree result_type, tree condition_operand,
tree true_operand, tree false_operand); tree true_operand, tree false_operand);
/* Similar, but for RETURN_EXPR. */ /* Similar, but for RETURN_EXPR. */
extern tree build_return_expr (tree result_decl, tree ret_val); extern tree build_return_expr (tree ret_obj, tree ret_val);
/* Build a CALL_EXPR to call FUNDECL with one argument, ARG. Return /* Build a CALL_EXPR to call FUNDECL with one argument, ARG. Return
the CALL_EXPR. */ the CALL_EXPR. */
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
* * * *
* C Implementation File * * C Implementation File *
* * * *
* Copyright (C) 1992-2009, Free Software Foundation, Inc. * * Copyright (C) 1992-2010, Free Software Foundation, Inc. *
* * * *
* GNAT is free software; you can redistribute it and/or modify it under * * GNAT is free software; you can redistribute it and/or modify it under *
* terms of the GNU General Public License as published by the Free Soft- * * terms of the GNU General Public License as published by the Free Soft- *
...@@ -609,6 +609,7 @@ build_binary_op (enum tree_code op_code, tree result_type, ...@@ -609,6 +609,7 @@ build_binary_op (enum tree_code op_code, tree result_type,
switch (op_code) switch (op_code)
{ {
case INIT_EXPR:
case MODIFY_EXPR: case MODIFY_EXPR:
/* If there were integral or pointer conversions on the LHS, remove /* If there were integral or pointer conversions on the LHS, remove
them; we'll be putting them back below if needed. Likewise for them; we'll be putting them back below if needed. Likewise for
...@@ -1397,45 +1398,40 @@ build_cond_expr (tree result_type, tree condition_operand, ...@@ -1397,45 +1398,40 @@ build_cond_expr (tree result_type, tree condition_operand,
return result; return result;
} }
/* Similar, but for RETURN_EXPR. If RESULT_DECL is non-zero, build /* Similar, but for RETURN_EXPR. If RET_VAL is non-null, build a RETURN_EXPR
a RETURN_EXPR around the assignment of RET_VAL to RESULT_DECL. around the assignment of RET_VAL to RET_OBJ. Otherwise just build a bare
If RESULT_DECL is zero, build a bare RETURN_EXPR. */ RETURN_EXPR around RESULT_OBJ, which may be null in this case. */
tree tree
build_return_expr (tree result_decl, tree ret_val) build_return_expr (tree ret_obj, tree ret_val)
{ {
tree result_expr; tree result_expr;
if (result_decl) if (ret_val)
{ {
/* The gimplifier explicitly enforces the following invariant: /* The gimplifier explicitly enforces the following invariant:
RETURN_EXPR RETURN_EXPR
| |
MODIFY_EXPR MODIFY_EXPR
/ \ / \
/ \ / \
RESULT_DECL ... RET_OBJ ...
As a consequence, type-homogeneity dictates that we use the type As a consequence, type consistency dictates that we use the type
of the RESULT_DECL as the operation type. */ of the RET_OBJ as the operation type. */
tree operation_type = TREE_TYPE (ret_obj);
tree operation_type = TREE_TYPE (result_decl);
/* Convert the right operand to the operation type. Note that
it's the same transformation as in the MODIFY_EXPR case of
build_binary_op with the additional guarantee that the type
cannot involve a placeholder, since otherwise the function
would use the "target pointer" return mechanism. */
/* Convert the right operand to the operation type. Note that it's the
same transformation as in the MODIFY_EXPR case of build_binary_op,
with the assumption that the type cannot involve a placeholder. */
if (operation_type != TREE_TYPE (ret_val)) if (operation_type != TREE_TYPE (ret_val))
ret_val = convert (operation_type, ret_val); ret_val = convert (operation_type, ret_val);
result_expr result_expr = build2 (MODIFY_EXPR, operation_type, ret_obj, ret_val);
= build2 (MODIFY_EXPR, operation_type, result_decl, ret_val);
} }
else else
result_expr = NULL_TREE; result_expr = ret_obj;
return build1 (RETURN_EXPR, void_type_node, result_expr); return build1 (RETURN_EXPR, void_type_node, result_expr);
} }
......
...@@ -2089,7 +2089,7 @@ expand_call (tree exp, rtx target, int ignore) ...@@ -2089,7 +2089,7 @@ expand_call (tree exp, rtx target, int ignore)
/* Set up a place to return a structure. */ /* Set up a place to return a structure. */
/* Cater to broken compilers. */ /* Cater to broken compilers. */
if (aggregate_value_p (exp, (!fndecl ? fntype : fndecl))) if (aggregate_value_p (exp, fntype))
{ {
/* This call returns a big structure. */ /* This call returns a big structure. */
flags &= ~(ECF_CONST | ECF_PURE | ECF_LOOPING_CONST_OR_PURE); flags &= ~(ECF_CONST | ECF_PURE | ECF_LOOPING_CONST_OR_PURE);
......
...@@ -1853,41 +1853,36 @@ struct rtl_opt_pass pass_instantiate_virtual_regs = ...@@ -1853,41 +1853,36 @@ struct rtl_opt_pass pass_instantiate_virtual_regs =
int int
aggregate_value_p (const_tree exp, const_tree fntype) aggregate_value_p (const_tree exp, const_tree fntype)
{ {
const_tree type = (TYPE_P (exp)) ? exp : TREE_TYPE (exp);
int i, regno, nregs; int i, regno, nregs;
rtx reg; rtx reg;
const_tree type = (TYPE_P (exp)) ? exp : TREE_TYPE (exp);
/* DECL node associated with FNTYPE when relevant, which we might need to
check for by-invisible-reference returns, typically for CALL_EXPR input
EXPressions. */
const_tree fndecl = NULL_TREE;
if (fntype) if (fntype)
switch (TREE_CODE (fntype)) switch (TREE_CODE (fntype))
{ {
case CALL_EXPR: case CALL_EXPR:
fndecl = get_callee_fndecl (fntype); {
fntype = (fndecl tree fndecl = get_callee_fndecl (fntype);
? TREE_TYPE (fndecl) fntype = (fndecl
: TREE_TYPE (TREE_TYPE (CALL_EXPR_FN (fntype)))); ? TREE_TYPE (fndecl)
: TREE_TYPE (TREE_TYPE (CALL_EXPR_FN (fntype))));
}
break; break;
case FUNCTION_DECL: case FUNCTION_DECL:
fndecl = fntype; fntype = TREE_TYPE (fntype);
fntype = TREE_TYPE (fndecl);
break; break;
case FUNCTION_TYPE: case FUNCTION_TYPE:
case METHOD_TYPE: case METHOD_TYPE:
break; break;
case IDENTIFIER_NODE: case IDENTIFIER_NODE:
fntype = 0; fntype = NULL_TREE;
break; break;
default: default:
/* We don't expect other rtl types here. */ /* We don't expect other tree types here. */
gcc_unreachable (); gcc_unreachable ();
} }
if (TREE_CODE (type) == VOID_TYPE) if (VOID_TYPE_P (type))
return 0; return 0;
/* If a record should be passed the same as its first (and only) member /* If a record should be passed the same as its first (and only) member
...@@ -1901,24 +1896,21 @@ aggregate_value_p (const_tree exp, const_tree fntype) ...@@ -1901,24 +1896,21 @@ aggregate_value_p (const_tree exp, const_tree fntype)
&& DECL_BY_REFERENCE (exp)) && DECL_BY_REFERENCE (exp))
return 1; return 1;
/* If the EXPression is a CALL_EXPR, honor DECL_BY_REFERENCE set on the /* Function types that are TREE_ADDRESSABLE force return in memory. */
called function RESULT_DECL, meaning the function returns in memory by if (fntype && TREE_ADDRESSABLE (fntype))
invisible reference. This check lets front-ends not set TREE_ADDRESSABLE
on the function type, which used to be the way to request such a return
mechanism but might now be causing troubles at gimplification time if
temporaries with the function type need to be created. */
if (TREE_CODE (exp) == CALL_EXPR && fndecl && DECL_RESULT (fndecl)
&& DECL_BY_REFERENCE (DECL_RESULT (fndecl)))
return 1; return 1;
if (targetm.calls.return_in_memory (type, fntype))
return 1;
/* Types that are TREE_ADDRESSABLE must be constructed in memory, /* Types that are TREE_ADDRESSABLE must be constructed in memory,
and thus can't be returned in registers. */ and thus can't be returned in registers. */
if (TREE_ADDRESSABLE (type)) if (TREE_ADDRESSABLE (type))
return 1; return 1;
if (flag_pcc_struct_return && AGGREGATE_TYPE_P (type)) if (flag_pcc_struct_return && AGGREGATE_TYPE_P (type))
return 1; return 1;
if (targetm.calls.return_in_memory (type, fntype))
return 1;
/* Make sure we have suitable call-clobbered regs to return /* Make sure we have suitable call-clobbered regs to return
the value in; if not, we must return it in memory. */ the value in; if not, we must return it in memory. */
reg = hard_function_value (type, 0, fntype, 0); reg = hard_function_value (type, 0, fntype, 0);
...@@ -1933,6 +1925,7 @@ aggregate_value_p (const_tree exp, const_tree fntype) ...@@ -1933,6 +1925,7 @@ aggregate_value_p (const_tree exp, const_tree fntype)
for (i = 0; i < nregs; i++) for (i = 0; i < nregs; i++)
if (! call_used_regs[regno + i]) if (! call_used_regs[regno + i])
return 1; return 1;
return 0; return 0;
} }
......
...@@ -4278,6 +4278,18 @@ gimplify_modify_expr_rhs (tree *expr_p, tree *from_p, tree *to_p, ...@@ -4278,6 +4278,18 @@ gimplify_modify_expr_rhs (tree *expr_p, tree *from_p, tree *to_p,
ret = GS_UNHANDLED; ret = GS_UNHANDLED;
break; break;
case WITH_SIZE_EXPR:
/* Likewise for calls that return an aggregate of non-constant size,
since we would not be able to generate a temporary at all. */
if (TREE_CODE (TREE_OPERAND (*from_p, 0)) == CALL_EXPR)
{
*from_p = TREE_OPERAND (*from_p, 0);
ret = GS_OK;
}
else
ret = GS_UNHANDLED;
break;
/* If we're initializing from a container, push the initialization /* If we're initializing from a container, push the initialization
inside it. */ inside it. */
case CLEANUP_POINT_EXPR: case CLEANUP_POINT_EXPR:
......
...@@ -1110,9 +1110,10 @@ extern void omp_clause_range_check_failed (const_tree, const char *, int, ...@@ -1110,9 +1110,10 @@ extern void omp_clause_range_check_failed (const_tree, const char *, int,
In CONSTRUCTOR nodes, it means object constructed must be in memory. In CONSTRUCTOR nodes, it means object constructed must be in memory.
In LABEL_DECL nodes, it means a goto for this label has been seen In LABEL_DECL nodes, it means a goto for this label has been seen
from a place outside all binding contours that restore stack levels. from a place outside all binding contours that restore stack levels.
In ..._TYPE nodes, it means that objects of this type must In ..._TYPE nodes, it means that objects of this type must be fully
be fully addressable. This means that pieces of this addressable. This means that pieces of this object cannot go into
object cannot go into register parameters, for example. register parameters, for example. If this a function type, this
means that the value must be returned in memory.
In IDENTIFIER_NODEs, this means that some extern decl for this name In IDENTIFIER_NODEs, this means that some extern decl for this name
had its address taken. That matters for inline functions. */ had its address taken. That matters for inline functions. */
#define TREE_ADDRESSABLE(NODE) ((NODE)->base.addressable_flag) #define TREE_ADDRESSABLE(NODE) ((NODE)->base.addressable_flag)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment