Commit 93e708f9 by Eric Botcazou Committed by Eric Botcazou

ada-tree.h (DECL_RETURN_VALUE_P): New macro.

	* gcc-interface/ada-tree.h (DECL_RETURN_VALUE_P): New macro.
	* gcc-interface/gigi.h (gigi): Remove useless attribute.
	(gnat_gimplify_expr): Likewise.
	(gnat_to_gnu_external): Declare.
	* gcc-interface/decl.c (gnat_to_gnu_entity) <E_Constant>: Factor out
	code dealing with the expression of external constants into...
	Invoke gnat_to_gnu_external instead.
	<E_Variable>: Invoke gnat_to_gnu_external to translate renamed objects
	when not for a definition.  Deal with COMPOUND_EXPR and variables with
	DECL_RETURN_VALUE_P set for renamings and with the case of a dangling
	'reference to a function call in a renaming.  Remove obsolete test and
	adjust associated comment.
	* gcc-interface/trans.c (Call_to_gnu): Set DECL_RETURN_VALUE_P on the
	temporaries created to hold the return value, if any.
	(gnat_to_gnu_external): ...this.  New function.
	* gcc-interface/utils.c (create_var_decl): Detect a constant created
	to hold 'reference to function call.
	* gcc-interface/utils2.c (build_unary_op) <ADDR_EXPR>: Add folding
	for COMPOUND_EXPR in the DECL_RETURN_VALUE_P case.

From-SVN: r233804
parent 6512bc93
2016-02-29 Eric Botcazou <ebotcazou@adacore.com>
* gcc-interface/ada-tree.h (DECL_RETURN_VALUE_P): New macro.
* gcc-interface/gigi.h (gigi): Remove useless attribute.
(gnat_gimplify_expr): Likewise.
(gnat_to_gnu_external): Declare.
* gcc-interface/decl.c (gnat_to_gnu_entity) <E_Constant>: Factor out
code dealing with the expression of external constants into...
Invoke gnat_to_gnu_external instead.
<E_Variable>: Invoke gnat_to_gnu_external to translate renamed objects
when not for a definition. Deal with COMPOUND_EXPR and variables with
DECL_RETURN_VALUE_P set for renamings and with the case of a dangling
'reference to a function call in a renaming. Remove obsolete test and
adjust associated comment.
* gcc-interface/trans.c (Call_to_gnu): Set DECL_RETURN_VALUE_P on the
temporaries created to hold the return value, if any.
(gnat_to_gnu_external): ...this. New function.
* gcc-interface/utils.c (create_var_decl): Detect a constant created
to hold 'reference to function call.
* gcc-interface/utils2.c (build_unary_op) <ADDR_EXPR>: Add folding
for COMPOUND_EXPR in the DECL_RETURN_VALUE_P case.
2016-02-17 Eric Botcazou <ebotcazou@adacore.com>
* exp_ch4.adb (Expand_N_Indexed_Component): Active synchronization if
......
......@@ -457,6 +457,10 @@ do { \
a discriminant of a discriminated type without default expression. */
#define DECL_INVARIANT_P(NODE) DECL_LANG_FLAG_4 (FIELD_DECL_CHECK (NODE))
/* Nonzero in a VAR_DECL if it is a temporary created to hold the return
value of a function call or 'reference to a function call. */
#define DECL_RETURN_VALUE_P(NODE) DECL_LANG_FLAG_5 (VAR_DECL_CHECK (NODE))
/* In a FIELD_DECL corresponding to a discriminant, contains the
discriminant number. */
#define DECL_DISCRIMINANT_NUMBER(NODE) DECL_INITIAL (FIELD_DECL_CHECK (NODE))
......
......@@ -552,31 +552,10 @@ gnat_to_gnu_entity (Entity_Id gnat_entity, tree gnu_expr, int definition)
&& Present (Expression (Declaration_Node (gnat_entity)))
&& Nkind (Expression (Declaration_Node (gnat_entity)))
!= N_Allocator)
{
bool went_into_elab_proc = false;
int save_force_global = force_global;
/* The expression may contain N_Expression_With_Actions nodes and
thus object declarations from other units. In this case, even
though the expression will eventually be discarded since not a
constant, the declarations would be stuck either in the global
varpool or in the current scope. Therefore we force the local
context and create a fake scope that we'll zap at the end. */
if (!current_function_decl)
{
current_function_decl = get_elaboration_procedure ();
went_into_elab_proc = true;
}
force_global = 0;
gnat_pushlevel ();
gnu_expr = gnat_to_gnu (Expression (Declaration_Node (gnat_entity)));
gnat_zaplevel ();
force_global = save_force_global;
if (went_into_elab_proc)
current_function_decl = NULL_TREE;
}
thus object declarations from other units. Discard them. */
gnu_expr
= gnat_to_gnu_external (Expression (Declaration_Node (gnat_entity)));
/* ... fall through ... */
......@@ -611,13 +590,17 @@ gnat_to_gnu_entity (Entity_Id gnat_entity, tree gnu_expr, int definition)
tree renamed_obj = NULL_TREE;
tree gnu_object_size;
/* We need to translate the renamed object even though we are only
referencing the renaming. But it may contain a call for which
we'll generate a temporary to hold the return value and which
is part of the definition of the renaming, so discard it. */
if (Present (Renamed_Object (gnat_entity)) && !definition)
{
if (kind == E_Exception)
gnu_expr = gnat_to_gnu_entity (Renamed_Entity (gnat_entity),
NULL_TREE, 0);
else
gnu_expr = gnat_to_gnu (Renamed_Object (gnat_entity));
gnu_expr = gnat_to_gnu_external (Renamed_Object (gnat_entity));
}
/* Get the type after elaborating the renamed object. */
......@@ -976,14 +959,39 @@ gnat_to_gnu_entity (Entity_Id gnat_entity, tree gnu_expr, int definition)
inner = TREE_OPERAND (inner, 0);
/* Expand_Dispatching_Call can prepend a comparison of the tags
before the call to "=". */
if (TREE_CODE (inner) == TRUTH_ANDIF_EXPR)
if (TREE_CODE (inner) == TRUTH_ANDIF_EXPR
|| TREE_CODE (inner) == COMPOUND_EXPR)
inner = TREE_OPERAND (inner, 1);
if ((TREE_CODE (inner) == CALL_EXPR
&& !call_is_atomic_load (inner))
|| TREE_CODE (inner) == ADDR_EXPR
|| TREE_CODE (inner) == NULL_EXPR
|| TREE_CODE (inner) == CONSTRUCTOR
|| CONSTANT_CLASS_P (inner))
|| CONSTANT_CLASS_P (inner)
/* We need to detect the case where a temporary is created to
hold the return value, since we cannot safely rename it at
top level as it lives only in the elaboration routine. */
|| (TREE_CODE (inner) == VAR_DECL
&& DECL_RETURN_VALUE_P (inner))
/* We also need to detect the case where the front-end creates
a dangling 'reference to a function call at top level and
substitutes it in the renaming, for example:
q__b : boolean renames r__f.e (1);
can be rewritten into:
q__R1s : constant q__A2s := r__f'reference;
[...]
q__b : boolean renames q__R1s.all.e (1);
We cannot safely rename the rewritten expression since the
underlying object lives only in the elaboration routine. */
|| (TREE_CODE (inner) == INDIRECT_REF
&& (inner
= remove_conversions (TREE_OPERAND (inner, 0), true))
&& TREE_CODE (inner) == VAR_DECL
&& DECL_RETURN_VALUE_P (inner)))
;
/* Case 2: if the renaming entity need not be materialized, use
......@@ -991,8 +999,7 @@ gnat_to_gnu_entity (Entity_Id gnat_entity, tree gnu_expr, int definition)
means that the caller is responsible for evaluating the address
of the renaming in the correct place for the definition case to
instantiate the SAVE_EXPRs. */
else if (TREE_CODE (inner) != COMPOUND_EXPR
&& !Materialize_Entity (gnat_entity))
else if (!Materialize_Entity (gnat_entity))
{
tree init = NULL_TREE;
......@@ -1001,7 +1008,7 @@ gnat_to_gnu_entity (Entity_Id gnat_entity, tree gnu_expr, int definition)
&init);
/* We cannot evaluate the first arm of a COMPOUND_EXPR in the
correct place for this case, hence the above test. */
correct place for this case. */
gcc_assert (!init);
/* No DECL_EXPR will be created so the expression needs to be
......
......@@ -246,7 +246,7 @@ extern "C" {
structures and then generates code. */
extern void gigi (Node_Id gnat_root,
int max_gnat_node,
int number_name ATTRIBUTE_UNUSED,
int number_name,
struct Node *nodes_ptr,
struct Flags *Flags_Ptr,
Node_Id *next_node_ptr,
......@@ -270,17 +270,19 @@ extern void gigi (Node_Id gnat_root,
#endif
/* GNAT_NODE is the root of some GNAT tree. Return the root of the
GCC tree corresponding to that GNAT tree. Normally, no code is generated;
we just return an equivalent tree which is used elsewhere to generate
code. */
GCC tree corresponding to that GNAT tree. */
extern tree gnat_to_gnu (Node_Id gnat_node);
/* Similar to gnat_to_gnu, but discard any object that might be created in
the course of the translation of GNAT_NODE, which must be an "external"
expression in the sense that it will be elaborated elsewhere. */
extern tree gnat_to_gnu_external (Node_Id gnat_node);
/* GNU_STMT is a statement. We generate code for that statement. */
extern void gnat_expand_stmt (tree gnu_stmt);
/* Generate GIMPLE in place for the expression at *EXPR_P. */
extern int gnat_gimplify_expr (tree *expr_p, gimple_seq *pre_p,
gimple_seq *post_p ATTRIBUTE_UNUSED);
extern int gnat_gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *);
/* Do the processing for the declaration of a GNAT_ENTITY, a type. If
a separate Freeze node exists, delay the bulk of the processing. Otherwise
......
......@@ -4336,7 +4336,10 @@ Call_to_gnu (Node_Id gnat_node, tree *gnu_result_type_p, tree gnu_target,
&& TREE_CODE (TYPE_SIZE (TREE_TYPE (gnu_target)))
== INTEGER_CST))
&& TREE_CODE (TYPE_SIZE (gnu_result_type)) != INTEGER_CST)))
gnu_retval = create_temporary ("R", gnu_result_type);
{
gnu_retval = create_temporary ("R", gnu_result_type);
DECL_RETURN_VALUE_P (gnu_retval) = 1;
}
/* Create the list of the actual parameters as GCC expects it, namely a
chain of TREE_LIST nodes in which the TREE_VALUE field of each node
......@@ -4461,7 +4464,10 @@ Call_to_gnu (Node_Id gnat_node, tree *gnu_result_type_p, tree gnu_target,
we need to create a temporary for the return value because we must
preserve it before copying back at the very end. */
if (!in_param && returning_value && !gnu_retval)
gnu_retval = create_temporary ("R", gnu_result_type);
{
gnu_retval = create_temporary ("R", gnu_result_type);
DECL_RETURN_VALUE_P (gnu_retval) = 1;
}
/* If we haven't pushed a binding level, push a new one. This will
narrow the lifetime of the temporary we are about to make as much
......@@ -7808,6 +7814,37 @@ gnat_to_gnu (Node_Id gnat_node)
return gnu_result;
}
/* Similar to gnat_to_gnu, but discard any object that might be created in
the course of the translation of GNAT_NODE, which must be an "external"
expression in the sense that it will be elaborated elsewhere. */
tree
gnat_to_gnu_external (Node_Id gnat_node)
{
const int save_force_global = force_global;
bool went_into_elab_proc = false;
/* Force the local context and create a fake scope that we zap
at the end so declarations will not be stuck either in the
global varpool or in the current scope. */
if (!current_function_decl)
{
current_function_decl = get_elaboration_procedure ();
went_into_elab_proc = true;
}
force_global = 0;
gnat_pushlevel ();
tree gnu_result = gnat_to_gnu (gnat_node);
gnat_zaplevel ();
force_global = save_force_global;
if (went_into_elab_proc)
current_function_decl = NULL_TREE;
return gnu_result;
}
/* Subroutine of above to push the exception label stack. GNU_STACK is
a pointer to the stack to update and GNAT_LABEL, if present, is the
......
......@@ -2464,6 +2464,22 @@ create_var_decl (tree name, tree asm_name, tree type, tree init,
&& !AGGREGATE_TYPE_P (type)) ? CONST_DECL : VAR_DECL,
name, type);
/* Detect constants created by the front-end to hold 'reference to function
calls for stabilization purposes. This is needed for renaming. */
if (const_flag && init && POINTER_TYPE_P (type))
{
tree inner = init;
if (TREE_CODE (inner) == COMPOUND_EXPR)
inner = TREE_OPERAND (inner, 1);
inner = remove_conversions (inner, true);
if (TREE_CODE (inner) == ADDR_EXPR
&& ((TREE_CODE (TREE_OPERAND (inner, 0)) == CALL_EXPR
&& !call_is_atomic_load (TREE_OPERAND (inner, 0)))
|| (TREE_CODE (TREE_OPERAND (inner, 0)) == VAR_DECL
&& DECL_RETURN_VALUE_P (TREE_OPERAND (inner, 0)))))
DECL_RETURN_VALUE_P (var_decl) = 1;
}
/* If this is external, throw away any initializations (they will be done
elsewhere) unless this is a constant for which we would like to remain
able to get the initializer. If we are defining a global here, leave a
......
......@@ -1383,8 +1383,11 @@ build_unary_op (enum tree_code op_code, tree result_type, tree operand)
since the middle-end cannot handle it. But we don't it in the
general case because it may introduce aliasing issues if the
first operand is an indirect assignment and the second operand
the corresponding address, e.g. for an allocator. */
if (TREE_CODE (type) == UNCONSTRAINED_ARRAY_TYPE)
the corresponding address, e.g. for an allocator. However do
it for a return value to expose it for later recognition. */
if (TREE_CODE (type) == UNCONSTRAINED_ARRAY_TYPE
|| (TREE_CODE (TREE_OPERAND (operand, 1)) == VAR_DECL
&& DECL_RETURN_VALUE_P (TREE_OPERAND (operand, 1))))
{
result = build_unary_op (ADDR_EXPR, result_type,
TREE_OPERAND (operand, 1));
......
2016-02-29 Eric Botcazou <ebotcazou@adacore.com>
* gnat.dg/renaming8.adb: New test.
* gnat.dg/renaming8_pkg1.ads: New helper.
* gnat.dg/renaming8_pkg2.ad[sb]: Likewise.
* gnat.dg/renaming8_pkg3.ad[sb]: Likewise.
2016-02-29 Richard Biener <rguenther@suse.de>
PR tree-optimization/69720
......
-- { dg-do run }
-- { dg-options "-gnatp" }
with Renaming8_Pkg1; use Renaming8_Pkg1;
procedure Renaming8 is
begin
if not B then
raise Program_Error;
end if;
end;
with Renaming8_Pkg2; use Renaming8_Pkg2;
package Renaming8_Pkg1 is
B: Boolean renames F.E(1);
end Renaming8_Pkg1;
package body Renaming8_Pkg2 is
function F return Rec is
begin
return (E => (others => True));
end;
end Renaming8_Pkg2;
with Renaming8_Pkg3; use Renaming8_Pkg3;
package Renaming8_Pkg2 is
type Arr is array (Positive range 1 .. Last_Index) of Boolean;
type Rec is record
E : Arr;
end record;
function F return Rec;
end Renaming8_Pkg2;
package body Renaming8_Pkg3 is
function Last_Index return Integer is
begin
return 16;
end;
end Renaming8_Pkg3;
package Renaming8_Pkg3 is
function Last_Index return Integer;
end Renaming8_Pkg3;
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