Commit 7194767c by Eric Botcazou Committed by Eric Botcazou

gigi.h (gnat_stabilize_reference): Adjust prototype.

	* gcc-interface/gigi.h (gnat_stabilize_reference): Adjust prototype.
	* gcc-interface/decl.c (gnat_to_gnu_entity): Do not rely on const_flag
 	to detect constant renamings.  Be prepared for specific pattern of
	renamed object based on function calls.  Create a constant object
	for the renaming of a NULL_EXPR or of a CONSTRUCTOR.  Adjust calls
	to gnat_stabilize_reference and tidy up.  Remove redundant tests.
	(elaborate_expression_1): Remove obsolete test and tidy up.
	* gcc-interface/trans.c (Call_to_gnu): Do not stabilize In/Out or Out
	parameters passed by reference.
	(gnat_to_gnu) <N_Selected_Component>: Remove redundant protection again
	side-effects.
	Use gnat_protect_expr instead of gnat_stabilize_reference for general
	protection against side-effects.
	* gcc-interface/utils2.c (gnat_stable_expr_p): New predicate.
	(gnat_save_expr): Invoke it.
	(gnat_protect_expr): Likewise.
	(gnat_stabilize_reference_1): Likewise.  Remove useless propagation
	of TREE_THIS_NOTRAP.
	(gnat_stabilize_reference): Remove parameter and adjust throughout.
	Delete ADDR_EXDR, COMPOUND_EXPR and CONSTRUCTOR cases.
	Restrict CALL_EXPR case to atomic loads and tweak ERROR_MARK case.

From-SVN: r223708
parent 517d07c9
2015-05-26 Eric Botcazou <ebotcazou@adacore.com>
* gcc-interface/gigi.h (gnat_stabilize_reference): Adjust prototype.
* gcc-interface/decl.c (gnat_to_gnu_entity): Do not rely on const_flag
to detect constant renamings. Be prepared for specific pattern of
renamed object based on function calls. Create a constant object
for the renaming of a NULL_EXPR or of a CONSTRUCTOR. Adjust calls
to gnat_stabilize_reference and tidy up. Remove redundant tests.
(elaborate_expression_1): Remove obsolete test and tidy up.
* gcc-interface/trans.c (Call_to_gnu): Do not stabilize In/Out or Out
parameters passed by reference.
(gnat_to_gnu) <N_Selected_Component>: Remove redundant protection again
side-effects.
Use gnat_protect_expr instead of gnat_stabilize_reference for general
protection against side-effects.
* gcc-interface/utils2.c (gnat_stable_expr_p): New predicate.
(gnat_save_expr): Invoke it.
(gnat_protect_expr): Likewise.
(gnat_stabilize_reference_1): Likewise. Remove useless propagation
of TREE_THIS_NOTRAP.
(gnat_stabilize_reference): Remove parameter and adjust throughout.
Delete ADDR_EXDR, COMPOUND_EXPR and CONSTRUCTOR cases.
Restrict CALL_EXPR case to atomic loads and tweak ERROR_MARK case.
2015-05-26 Ed Schonberg <schonberg@adacore.com> 2015-05-26 Ed Schonberg <schonberg@adacore.com>
* sinfo.ads: Minor reformatting. * sinfo.ads: Minor reformatting.
......
...@@ -955,13 +955,12 @@ gnat_to_gnu_entity (Entity_Id gnat_entity, tree gnu_expr, int definition) ...@@ -955,13 +955,12 @@ gnat_to_gnu_entity (Entity_Id gnat_entity, tree gnu_expr, int definition)
} }
/* If this is a renaming, avoid as much as possible to create a new /* If this is a renaming, avoid as much as possible to create a new
object. However, in several cases, creating it is required. object. However, in some cases, creating it is required because
This processing needs to be applied to the raw expression so renaming can be applied to objects that are not names in Ada.
as to make it more likely to rename the underlying object. */ This processing needs to be applied to the raw expression so as
to make it more likely to rename the underlying object. */
if (Present (Renamed_Object (gnat_entity))) if (Present (Renamed_Object (gnat_entity)))
{ {
bool create_normal_object = false;
/* If the renamed object had padding, strip off the reference /* If the renamed object had padding, strip off the reference
to the inner object and reset our type. */ to the inner object and reset our type. */
if ((TREE_CODE (gnu_expr) == COMPONENT_REF if ((TREE_CODE (gnu_expr) == COMPONENT_REF
...@@ -981,82 +980,64 @@ gnat_to_gnu_entity (Entity_Id gnat_entity, tree gnu_expr, int definition) ...@@ -981,82 +980,64 @@ gnat_to_gnu_entity (Entity_Id gnat_entity, tree gnu_expr, int definition)
&& CONTAINS_PLACEHOLDER_P (TYPE_SIZE (gnu_type))) && CONTAINS_PLACEHOLDER_P (TYPE_SIZE (gnu_type)))
gnu_type = TREE_TYPE (gnu_expr); gnu_type = TREE_TYPE (gnu_expr);
/* Case 1: If this is a constant renaming stemming from a function /* Case 1: if this is a constant renaming stemming from a function
call, treat it as a normal object whose initial value is what is call, treat it as a normal object whose initial value is what
being renamed. RM 3.3 says that the result of evaluating a is being renamed. RM 3.3 says that the result of evaluating a
function call is a constant object. Treat constant literals function call is a constant object. Therefore, it can be the
the same way. As a consequence, it can be the inner object of inner object of a constant renaming and the renaming must be
a constant renaming. In this case, the renaming must be fully fully instantiated, i.e. it cannot be a reference to (part of)
instantiated, i.e. it cannot be a mere reference to (part of) an an existing object. And treat null expressions, constructors
existing object. */ and literals the same way. */
if (const_flag) tree inner = gnu_expr;
{ while (handled_component_p (inner) || CONVERT_EXPR_P (inner))
tree inner_object = gnu_expr; inner = TREE_OPERAND (inner, 0);
while (handled_component_p (inner_object)) /* Expand_Dispatching_Call can prepend a comparison of the tags
inner_object = TREE_OPERAND (inner_object, 0); before the call to "=". */
if (TREE_CODE (inner_object) == CALL_EXPR if (TREE_CODE (inner) == TRUTH_ANDIF_EXPR)
|| CONSTANT_CLASS_P (inner_object)) inner = TREE_OPERAND (inner, 1);
create_normal_object = true; if (TREE_CODE (inner) == CALL_EXPR
} || TREE_CODE (inner) == NULL_EXPR
|| TREE_CODE (inner) == CONSTRUCTOR
/* Otherwise, see if we can proceed with a stabilized version of || CONSTANT_CLASS_P (inner))
the renamed entity or if we need to make a new object. */ ;
if (!create_normal_object)
{ /* Case 2: if the renaming entity need not be materialized, use
tree maybe_stable_expr = NULL_TREE; the stabilized renamed expression for the renaming. At the
bool stable = false; global level, we can do this only if we know no SAVE_EXPRs
need be made, because otherwise the expression would be tied
/* Case 2: If the renaming entity need not be materialized and to a specific elaboration routine. */
the renamed expression is something we can stabilize, use else if (!Materialize_Entity (gnat_entity)
that for the renaming. At the global level, we can only do && (!global_bindings_p ()
this if we know no SAVE_EXPRs need be made, because the
expression we return might be used in arbitrary conditional
branches so we must force the evaluation of the SAVE_EXPRs
immediately and this requires a proper function context.
Note that an external constant is at the global level. */
if (!Materialize_Entity (gnat_entity)
&& (!((!definition && kind == E_Constant)
|| global_bindings_p ())
|| (staticp (gnu_expr) || (staticp (gnu_expr)
&& !TREE_SIDE_EFFECTS (gnu_expr)))) && !TREE_SIDE_EFFECTS (gnu_expr))))
{ {
maybe_stable_expr gnu_decl = gnat_stabilize_reference (gnu_expr, true);
= gnat_stabilize_reference (gnu_expr, true, &stable);
if (stable)
{
/* ??? No DECL_EXPR is created so we need to mark /* ??? No DECL_EXPR is created so we need to mark
the expression manually lest it is shared. */ the expression manually lest it is shared. */
if ((!definition && kind == E_Constant) if (global_bindings_p ())
|| global_bindings_p ()) MARK_VISITED (gnu_decl);
MARK_VISITED (maybe_stable_expr);
gnu_decl = maybe_stable_expr; /* This assertion will fail if the renamed object isn't
save_gnu_tree (gnat_entity, gnu_decl, true); aligned enough as to make it possible to honor the
saved = true; alignment set on the renaming. */
annotate_object (gnat_entity, gnu_type, NULL_TREE,
false);
/* This assertion will fail if the renamed object
isn't aligned enough as to make it possible to
honor the alignment set on the renaming. */
if (align) if (align)
{ {
unsigned int renamed_align unsigned int ralign = DECL_P (gnu_decl)
= DECL_P (gnu_decl)
? DECL_ALIGN (gnu_decl) ? DECL_ALIGN (gnu_decl)
: TYPE_ALIGN (TREE_TYPE (gnu_decl)); : TYPE_ALIGN (TREE_TYPE (gnu_decl));
gcc_assert (renamed_align >= align); gcc_assert (ralign >= align);
}
break;
} }
/* The stabilization failed. Keep maybe_stable_expr save_gnu_tree (gnat_entity, gnu_decl, true);
untouched here to let the pointer case below know saved = true;
about that failure. */ annotate_object (gnat_entity, gnu_type, NULL_TREE, false);
break;
} }
/* Case 3: Make this into a constant pointer to the object we /* Case 3: otherwise, make a constant pointer to the object we
are to rename and attach the object to the pointer if it is are to rename and attach the object to the pointer after it
something we can stabilize. is stabilized.
From the proper scope, attached objects will be referenced From the proper scope, attached objects will be referenced
directly instead of indirectly via the pointer to avoid directly instead of indirectly via the pointer to avoid
...@@ -1065,12 +1046,10 @@ gnat_to_gnu_entity (Entity_Id gnat_entity, tree gnu_expr, int definition) ...@@ -1065,12 +1046,10 @@ gnat_to_gnu_entity (Entity_Id gnat_entity, tree gnu_expr, int definition)
variables in the expression every time the renaming is used. variables in the expression every time the renaming is used.
The pointer is called a "renaming" pointer in this case. The pointer is called a "renaming" pointer in this case.
In the rare cases where we cannot stabilize the renamed
object, we just make a "bare" pointer and the renamed
object will always be accessed indirectly through it.
Note that we need to preserve the volatility of the renamed Note that we need to preserve the volatility of the renamed
object through the indirection. */ object through the indirection. */
else
{
if (TREE_THIS_VOLATILE (gnu_expr) && !TYPE_VOLATILE (gnu_type)) if (TREE_THIS_VOLATILE (gnu_expr) && !TYPE_VOLATILE (gnu_type))
gnu_type gnu_type
= change_qualified_type (gnu_type, TYPE_QUAL_VOLATILE); = change_qualified_type (gnu_type, TYPE_QUAL_VOLATILE);
...@@ -1078,15 +1057,7 @@ gnat_to_gnu_entity (Entity_Id gnat_entity, tree gnu_expr, int definition) ...@@ -1078,15 +1057,7 @@ gnat_to_gnu_entity (Entity_Id gnat_entity, tree gnu_expr, int definition)
inner_const_flag = TREE_READONLY (gnu_expr); inner_const_flag = TREE_READONLY (gnu_expr);
const_flag = true; const_flag = true;
/* If the previous attempt at stabilizing failed, there is /* Stabilize and attach the expression to the pointer.
no point in trying again and we reuse the result without
attaching it to the pointer. In this case it will only
be used as the initializing expression of the pointer and
thus needs no special treatment with regard to multiple
evaluations.
Otherwise, try to stabilize and attach the expression to
the pointer if the stabilization succeeds.
Note that this might introduce SAVE_EXPRs and we don't Note that this might introduce SAVE_EXPRs and we don't
check whether we are at the global level or not. This check whether we are at the global level or not. This
...@@ -1100,21 +1071,14 @@ gnat_to_gnu_entity (Entity_Id gnat_entity, tree gnu_expr, int definition) ...@@ -1100,21 +1071,14 @@ gnat_to_gnu_entity (Entity_Id gnat_entity, tree gnu_expr, int definition)
non-global case or the elaboration code for the global non-global case or the elaboration code for the global
case, and will be attached to the elaboration procedure case, and will be attached to the elaboration procedure
in the latter case. */ in the latter case. */
if (!maybe_stable_expr) renamed_obj = gnat_stabilize_reference (gnu_expr, true);
{
maybe_stable_expr
= gnat_stabilize_reference (gnu_expr, true, &stable);
if (stable)
renamed_obj = maybe_stable_expr;
}
if (type_annotate_only if (type_annotate_only
&& TREE_CODE (maybe_stable_expr) == ERROR_MARK) && TREE_CODE (renamed_obj) == ERROR_MARK)
gnu_expr = NULL_TREE; gnu_expr = NULL_TREE;
else else
gnu_expr gnu_expr
= build_unary_op (ADDR_EXPR, gnu_type, maybe_stable_expr); = build_unary_op (ADDR_EXPR, gnu_type, renamed_obj);
gnu_size = NULL_TREE; gnu_size = NULL_TREE;
used_by_ref = true; used_by_ref = true;
...@@ -1519,13 +1483,12 @@ gnat_to_gnu_entity (Entity_Id gnat_entity, tree gnu_expr, int definition) ...@@ -1519,13 +1483,12 @@ gnat_to_gnu_entity (Entity_Id gnat_entity, tree gnu_expr, int definition)
/* If this is a renaming pointer, attach the renamed object to it and /* If this is a renaming pointer, attach the renamed object to it and
register it if we are at the global level and the renamed object register it if we are at the global level and the renamed object
is a non-constant reference. Note that an external constant is at is a non-constant reference. */
the global level. */
if (renamed_obj) if (renamed_obj)
{ {
SET_DECL_RENAMED_OBJECT (gnu_decl, renamed_obj); SET_DECL_RENAMED_OBJECT (gnu_decl, renamed_obj);
if (((!definition && kind == E_Constant) || global_bindings_p ()) if (global_bindings_p ()
&& !gnat_constant_reference_p (renamed_obj)) && !gnat_constant_reference_p (renamed_obj))
{ {
DECL_GLOBAL_NONCONSTANT_RENAMING_P (gnu_decl) = 1; DECL_GLOBAL_NONCONSTANT_RENAMING_P (gnu_decl) = 1;
...@@ -6197,16 +6160,6 @@ elaborate_expression_1 (tree gnu_expr, Entity_Id gnat_entity, const char *s, ...@@ -6197,16 +6160,6 @@ elaborate_expression_1 (tree gnu_expr, Entity_Id gnat_entity, const char *s,
const bool expr_global_p = expr_public_p || global_bindings_p (); const bool expr_global_p = expr_public_p || global_bindings_p ();
bool expr_variable_p, use_variable; bool expr_variable_p, use_variable;
/* In most cases, we won't see a naked FIELD_DECL because a discriminant
reference will have been replaced with a COMPONENT_REF when the type
is being elaborated. However, there are some cases involving child
types where we will. So convert it to a COMPONENT_REF. We hope it
will be at the highest level of the expression in these cases. */
if (TREE_CODE (gnu_expr) == FIELD_DECL)
gnu_expr = build3 (COMPONENT_REF, TREE_TYPE (gnu_expr),
build0 (PLACEHOLDER_EXPR, DECL_CONTEXT (gnu_expr)),
gnu_expr, NULL_TREE);
/* If GNU_EXPR contains a placeholder, just return it. We rely on the fact /* If GNU_EXPR contains a placeholder, just return it. We rely on the fact
that an expression cannot contain both a discriminant and a variable. */ that an expression cannot contain both a discriminant and a variable. */
if (CONTAINS_PLACEHOLDER_P (gnu_expr)) if (CONTAINS_PLACEHOLDER_P (gnu_expr))
...@@ -6217,14 +6170,12 @@ elaborate_expression_1 (tree gnu_expr, Entity_Id gnat_entity, const char *s, ...@@ -6217,14 +6170,12 @@ elaborate_expression_1 (tree gnu_expr, Entity_Id gnat_entity, const char *s,
containing the definition is elaborated. If this entity is defined at top containing the definition is elaborated. If this entity is defined at top
level, replace the expression by the variable; otherwise use a SAVE_EXPR level, replace the expression by the variable; otherwise use a SAVE_EXPR
if this is necessary. */ if this is necessary. */
if (CONSTANT_CLASS_P (gnu_expr)) if (TREE_CONSTANT (gnu_expr))
expr_variable_p = false; expr_variable_p = false;
else else
{ {
/* Skip any conversions and simple constant arithmetics to see if the /* Skip any conversions and simple constant arithmetics to see if the
expression is based on a read-only variable. expression is based on a read-only variable. */
??? This really should remain read-only, but we have to think about
the typing of the tree here. */
tree inner = remove_conversions (gnu_expr, true); tree inner = remove_conversions (gnu_expr, true);
inner = skip_simple_constant_arithmetic (inner); inner = skip_simple_constant_arithmetic (inner);
......
...@@ -965,9 +965,8 @@ extern tree gnat_protect_expr (tree exp); ...@@ -965,9 +965,8 @@ extern tree gnat_protect_expr (tree exp);
/* This is equivalent to stabilize_reference in tree.c but we know how to /* This is equivalent to stabilize_reference in tree.c but we know how to
handle our own nodes and we take extra arguments. FORCE says whether to handle our own nodes and we take extra arguments. FORCE says whether to
force evaluation of everything. We set SUCCESS to true unless we walk force evaluation of everything. */
through something we don't know how to stabilize. */ extern tree gnat_stabilize_reference (tree ref, bool force);
extern tree gnat_stabilize_reference (tree ref, bool force, bool *success);
/* This is equivalent to get_inner_reference in expr.c but it returns the /* This is equivalent to get_inner_reference in expr.c but it returns the
ultimate containing object only if the reference (lvalue) is constant, ultimate containing object only if the reference (lvalue) is constant,
......
...@@ -4241,11 +4241,11 @@ Call_to_gnu (Node_Id gnat_node, tree *gnu_result_type_p, tree gnu_target, ...@@ -4241,11 +4241,11 @@ Call_to_gnu (Node_Id gnat_node, tree *gnu_result_type_p, tree gnu_target,
/* If it's possible we may need to use this expression twice, make sure /* If it's possible we may need to use this expression twice, make sure
that any side-effects are handled via SAVE_EXPRs; likewise if we need that any side-effects are handled via SAVE_EXPRs; likewise if we need
to force side-effects before the call. to force side-effects before the call. */
??? This is more conservative than we need since we don't need to do if (Ekind (gnat_formal) != E_In_Parameter
this for pass-by-ref with no conversion. */ && !is_by_ref_formal_parm
if (Ekind (gnat_formal) != E_In_Parameter) && TREE_CODE (gnu_name) != NULL_EXPR)
gnu_name = gnat_stabilize_reference (gnu_name, true, NULL); gnu_name = gnat_stabilize_reference (gnu_name, true);
/* If we are passing a non-addressable parameter by reference, pass the /* If we are passing a non-addressable parameter by reference, pass the
address of a copy. In the Out or In Out case, set up to copy back address of a copy. In the Out or In Out case, set up to copy back
...@@ -6099,14 +6099,6 @@ gnat_to_gnu (Node_Id gnat_node) ...@@ -6099,14 +6099,6 @@ gnat_to_gnu (Node_Id gnat_node)
{ {
gnu_field = gnat_to_gnu_field_decl (gnat_field); gnu_field = gnat_to_gnu_field_decl (gnat_field);
/* If there are discriminants, the prefix might be evaluated more
than once, which is a problem if it has side-effects. */
if (Has_Discriminants (Is_Access_Type (Etype (Prefix (gnat_node)))
? Designated_Type (Etype
(Prefix (gnat_node)))
: Etype (Prefix (gnat_node))))
gnu_prefix = gnat_stabilize_reference (gnu_prefix, false, NULL);
gnu_result gnu_result
= build_component_ref (gnu_prefix, NULL_TREE, gnu_field, = build_component_ref (gnu_prefix, NULL_TREE, gnu_field,
(Nkind (Parent (gnat_node)) (Nkind (Parent (gnat_node))
...@@ -7313,7 +7305,6 @@ gnat_to_gnu (Node_Id gnat_node) ...@@ -7313,7 +7305,6 @@ gnat_to_gnu (Node_Id gnat_node)
gets inserted there as well. This ensures that the type elaboration gets inserted there as well. This ensures that the type elaboration
code is issued past the actions computing values on which it might code is issued past the actions computing values on which it might
depend. */ depend. */
start_stmt_group (); start_stmt_group ();
add_stmt_list (Actions (gnat_node)); add_stmt_list (Actions (gnat_node));
gnu_expr = gnat_to_gnu (Expression (gnat_node)); gnu_expr = gnat_to_gnu (Expression (gnat_node));
...@@ -7498,7 +7489,7 @@ gnat_to_gnu (Node_Id gnat_node) ...@@ -7498,7 +7489,7 @@ gnat_to_gnu (Node_Id gnat_node)
&& TYPE_IS_PADDING_P (TREE_TYPE (gnu_result))) && TYPE_IS_PADDING_P (TREE_TYPE (gnu_result)))
&& (TREE_CODE (gnu_result_type) == UNCONSTRAINED_ARRAY_TYPE && (TREE_CODE (gnu_result_type) == UNCONSTRAINED_ARRAY_TYPE
|| CONTAINS_PLACEHOLDER_P (TYPE_SIZE (gnu_result_type)))) || CONTAINS_PLACEHOLDER_P (TYPE_SIZE (gnu_result_type))))
gnu_result = gnat_stabilize_reference (gnu_result, false, NULL); gnu_result = gnat_protect_expr (gnu_result);
/* Now convert the result to the result type, unless we are in one of the /* Now convert the result to the result type, unless we are in one of the
following cases: following cases:
......
...@@ -2563,6 +2563,17 @@ gnat_mark_addressable (tree t) ...@@ -2563,6 +2563,17 @@ gnat_mark_addressable (tree t)
} }
} }
/* Return true if EXP is a stable expression for the purpose of the functions
below and, therefore, can be returned unmodified by them. We accept things
that are actual constants or that have already been handled. */
static bool
gnat_stable_expr_p (tree exp)
{
enum tree_code code = TREE_CODE (exp);
return TREE_CONSTANT (exp) || code == NULL_EXPR || code == SAVE_EXPR;
}
/* Save EXP for later use or reuse. This is equivalent to save_expr in tree.c /* Save EXP for later use or reuse. This is equivalent to save_expr in tree.c
but we know how to handle our own nodes. */ but we know how to handle our own nodes. */
...@@ -2572,7 +2583,7 @@ gnat_save_expr (tree exp) ...@@ -2572,7 +2583,7 @@ gnat_save_expr (tree exp)
tree type = TREE_TYPE (exp); tree type = TREE_TYPE (exp);
enum tree_code code = TREE_CODE (exp); enum tree_code code = TREE_CODE (exp);
if (TREE_CONSTANT (exp) || code == SAVE_EXPR || code == NULL_EXPR) if (gnat_stable_expr_p (exp))
return exp; return exp;
if (code == UNCONSTRAINED_ARRAY_REF) if (code == UNCONSTRAINED_ARRAY_REF)
...@@ -2603,7 +2614,7 @@ gnat_protect_expr (tree exp) ...@@ -2603,7 +2614,7 @@ gnat_protect_expr (tree exp)
tree type = TREE_TYPE (exp); tree type = TREE_TYPE (exp);
enum tree_code code = TREE_CODE (exp); enum tree_code code = TREE_CODE (exp);
if (TREE_CONSTANT (exp) || code == SAVE_EXPR || code == NULL_EXPR) if (gnat_stable_expr_p (exp))
return exp; return exp;
/* If EXP has no side effects, we theoretically don't need to do anything. /* If EXP has no side effects, we theoretically don't need to do anything.
...@@ -2669,11 +2680,7 @@ gnat_stabilize_reference_1 (tree e, bool force) ...@@ -2669,11 +2680,7 @@ gnat_stabilize_reference_1 (tree e, bool force)
tree type = TREE_TYPE (e); tree type = TREE_TYPE (e);
tree result; tree result;
/* We cannot ignore const expressions because it might be a reference if (gnat_stable_expr_p (e))
to a const array but whose index contains side-effects. But we can
ignore things that are actual constant or that already have been
handled by this function. */
if (TREE_CONSTANT (e) || code == SAVE_EXPR)
return e; return e;
switch (TREE_CODE_CLASS (code)) switch (TREE_CODE_CLASS (code))
...@@ -2722,36 +2729,24 @@ gnat_stabilize_reference_1 (tree e, bool force) ...@@ -2722,36 +2729,24 @@ gnat_stabilize_reference_1 (tree e, bool force)
gcc_unreachable (); gcc_unreachable ();
} }
/* See similar handling in gnat_stabilize_reference. */
TREE_READONLY (result) = TREE_READONLY (e); TREE_READONLY (result) = TREE_READONLY (e);
TREE_SIDE_EFFECTS (result) |= TREE_SIDE_EFFECTS (e); TREE_SIDE_EFFECTS (result) |= TREE_SIDE_EFFECTS (e);
TREE_THIS_VOLATILE (result) = TREE_THIS_VOLATILE (e); TREE_THIS_VOLATILE (result) = TREE_THIS_VOLATILE (e);
if (code == INDIRECT_REF
|| code == UNCONSTRAINED_ARRAY_REF
|| code == ARRAY_REF
|| code == ARRAY_RANGE_REF)
TREE_THIS_NOTRAP (result) = TREE_THIS_NOTRAP (e);
return result; return result;
} }
/* This is equivalent to stabilize_reference in tree.c but we know how to /* This is equivalent to stabilize_reference in tree.c but we know how to
handle our own nodes and we take extra arguments. FORCE says whether to handle our own nodes and we take extra arguments. FORCE says whether to
force evaluation of everything. We set SUCCESS to true unless we walk force evaluation of everything. */
through something we don't know how to stabilize. */
tree tree
gnat_stabilize_reference (tree ref, bool force, bool *success) gnat_stabilize_reference (tree ref, bool force)
{ {
tree type = TREE_TYPE (ref); tree type = TREE_TYPE (ref);
enum tree_code code = TREE_CODE (ref); enum tree_code code = TREE_CODE (ref);
tree result; tree result;
/* Assume we'll success unless proven otherwise. */
if (success)
*success = true;
switch (code) switch (code)
{ {
case CONST_DECL: case CONST_DECL:
...@@ -2761,15 +2756,13 @@ gnat_stabilize_reference (tree ref, bool force, bool *success) ...@@ -2761,15 +2756,13 @@ gnat_stabilize_reference (tree ref, bool force, bool *success)
/* No action is needed in this case. */ /* No action is needed in this case. */
return ref; return ref;
case ADDR_EXPR:
CASE_CONVERT: CASE_CONVERT:
case FLOAT_EXPR: case FLOAT_EXPR:
case FIX_TRUNC_EXPR: case FIX_TRUNC_EXPR:
case VIEW_CONVERT_EXPR: case VIEW_CONVERT_EXPR:
result result
= build1 (code, type, = build1 (code, type,
gnat_stabilize_reference (TREE_OPERAND (ref, 0), force, gnat_stabilize_reference (TREE_OPERAND (ref, 0), force));
success));
break; break;
case INDIRECT_REF: case INDIRECT_REF:
...@@ -2781,79 +2774,51 @@ gnat_stabilize_reference (tree ref, bool force, bool *success) ...@@ -2781,79 +2774,51 @@ gnat_stabilize_reference (tree ref, bool force, bool *success)
case COMPONENT_REF: case COMPONENT_REF:
result = build3 (COMPONENT_REF, type, result = build3 (COMPONENT_REF, type,
gnat_stabilize_reference (TREE_OPERAND (ref, 0), force, gnat_stabilize_reference (TREE_OPERAND (ref, 0), force),
success),
TREE_OPERAND (ref, 1), NULL_TREE); TREE_OPERAND (ref, 1), NULL_TREE);
break; break;
case BIT_FIELD_REF: case BIT_FIELD_REF:
result = build3 (BIT_FIELD_REF, type, result = build3 (BIT_FIELD_REF, type,
gnat_stabilize_reference (TREE_OPERAND (ref, 0), force, gnat_stabilize_reference (TREE_OPERAND (ref, 0), force),
success),
TREE_OPERAND (ref, 1), TREE_OPERAND (ref, 2)); TREE_OPERAND (ref, 1), TREE_OPERAND (ref, 2));
break; break;
case ARRAY_REF: case ARRAY_REF:
case ARRAY_RANGE_REF: case ARRAY_RANGE_REF:
result = build4 (code, type,
gnat_stabilize_reference (TREE_OPERAND (ref, 0), force,
success),
gnat_stabilize_reference_1 (TREE_OPERAND (ref, 1),
force),
NULL_TREE, NULL_TREE);
break;
case CALL_EXPR:
if (call_is_atomic_load (ref))
result result
= build_call_expr (TREE_OPERAND (CALL_EXPR_FN (ref), 0), 2, = build4 (code, type,
gnat_stabilize_reference (CALL_EXPR_ARG (ref, 0), gnat_stabilize_reference (TREE_OPERAND (ref, 0), force),
force, success), gnat_stabilize_reference_1 (TREE_OPERAND (ref, 1), force),
CALL_EXPR_ARG (ref, 1)); TREE_OPERAND (ref, 2), TREE_OPERAND (ref, 3));
else
result = gnat_stabilize_reference_1 (ref, force);
break;
case COMPOUND_EXPR:
result = build2 (COMPOUND_EXPR, type,
gnat_stabilize_reference (TREE_OPERAND (ref, 0), force,
success),
gnat_stabilize_reference (TREE_OPERAND (ref, 1), force,
success));
break; break;
case CONSTRUCTOR: case CALL_EXPR:
/* Constructors with 1 element are used extensively to formally
convert objects to special wrapping types. */
if (TREE_CODE (type) == RECORD_TYPE
&& vec_safe_length (CONSTRUCTOR_ELTS (ref)) == 1)
{ {
tree index = (*CONSTRUCTOR_ELTS (ref))[0].index; /* This can only be an atomic load. */
tree value = (*CONSTRUCTOR_ELTS (ref))[0].value; gcc_assert (call_is_atomic_load (ref));
result
= build_constructor_single (type, index, /* An atomic load is an INDIRECT_REF of its first argument. */
gnat_stabilize_reference_1 (value, tree t = CALL_EXPR_ARG (ref, 0);
force)); if (TREE_CODE (t) == NOP_EXPR)
} t = TREE_OPERAND (t, 0);
if (TREE_CODE (t) == ADDR_EXPR)
t = build1 (ADDR_EXPR, TREE_TYPE (t),
gnat_stabilize_reference (TREE_OPERAND (t, 0), force));
else else
{ t = gnat_stabilize_reference_1 (t, force);
if (success) t = fold_convert (TREE_TYPE (CALL_EXPR_ARG (ref, 0)), t);
*success = false;
return ref; result = build_call_expr (TREE_OPERAND (CALL_EXPR_FN (ref), 0), 2,
t, CALL_EXPR_ARG (ref, 1));
} }
break; break;
case ERROR_MARK: case ERROR_MARK:
ref = error_mark_node; return error_mark_node;
/* ... fall through to failure ... */
/* If arg isn't a kind of lvalue we recognize, make no change.
Caller should recognize the error for an invalid lvalue. */
default: default:
if (success) gcc_unreachable ();
*success = false;
return ref;
} }
/* TREE_THIS_VOLATILE and TREE_SIDE_EFFECTS set on the initial expression /* TREE_THIS_VOLATILE and TREE_SIDE_EFFECTS set on the initial expression
......
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