Commit 241125b2 by Eric Botcazou Committed by Eric Botcazou

ada-tree.h (DECL_GLOBAL_NONCONSTANT_RENAMING_P): Delete

	* gcc-interface/ada-tree.h (DECL_GLOBAL_NONCONSTANT_RENAMING_P): Delete
	(DECL_RENAMED_OBJECT): Adjust comment.
	* gcc-interface/gigi.h (record_global_nonconstant_renaming): Delete.
	(invalidate_global_nonconstant_renamings): Likewise.
	(gnat_constant_reference_p): Likewise.
	(rewrite_fn): New function type.
	(gnat_rewrite_reference): Declare.
	(call_is_atomic_load): New inline predicate.
	* gcc-interface/decl.c (elaborate_reference_1): New function.
	(elaborate_reference): Likewise.
	(gnat_to_gnu_entity): Call elaborate_reference to elaborate renamings
	and simplify associated code.  Set const_flag to true consistently in
 	conjunction with used_by_ref.
	* gcc-interface/trans.c (Identifier_to_gnu): Always replace renaming
	pointers by renamed objects.
	(outer_atomic_access_required_p): Deal with renamings.
	(Compilation_Unit_to_gnu): Do not call
	invalidate_global_nonconstant_renamings.
	(gnat_to_gnu) <N_Object_Renaming_Declaration>: Adjust comment.
	(gnat_gimplify_expr): Deal with atomic loads.
	* gcc-interface/utils.c (global_nonconstant_renamings): Delete.
	(destroy_gnat_utils): Do not call
	invalidate_global_nonconstant_renamings.
	(record_global_nonconstant_renaming): Delete.
	(invalidate_global_nonconstant_renamings): Likewise.
	* gcc-interface/utils2.c (call_is_atomic_load): Move to gigi.h.
	(build_load_modify_store): Build a copy of the destination.
	(gnat_stabilize_reference_1): Adjust.
	(gnat_stabilize_reference): Call gnat_stabilize_reference_1 through
	gnat_rewrite_reference and move bulk of code to...
	(gnat_rewrite_reference): ...here.  New global function.
	(gnat_constant_reference_p): Delete.

From-SVN: r223709
parent 7194767c
2015-05-26 Eric Botcazou <ebotcazou@adacore.com> 2015-05-26 Eric Botcazou <ebotcazou@adacore.com>
* gcc-interface/ada-tree.h (DECL_GLOBAL_NONCONSTANT_RENAMING_P): Delete
(DECL_RENAMED_OBJECT): Adjust comment.
* gcc-interface/gigi.h (record_global_nonconstant_renaming): Delete.
(invalidate_global_nonconstant_renamings): Likewise.
(gnat_constant_reference_p): Likewise.
(rewrite_fn): New function type.
(gnat_rewrite_reference): Declare.
(call_is_atomic_load): New inline predicate.
* gcc-interface/decl.c (elaborate_reference_1): New function.
(elaborate_reference): Likewise.
(gnat_to_gnu_entity): Call elaborate_reference to elaborate renamings
and simplify associated code. Set const_flag to true consistently in
conjunction with used_by_ref.
* gcc-interface/trans.c (Identifier_to_gnu): Always replace renaming
pointers by renamed objects.
(outer_atomic_access_required_p): Deal with renamings.
(Compilation_Unit_to_gnu): Do not call
invalidate_global_nonconstant_renamings.
(gnat_to_gnu) <N_Object_Renaming_Declaration>: Adjust comment.
(gnat_gimplify_expr): Deal with atomic loads.
* gcc-interface/utils.c (global_nonconstant_renamings): Delete.
(destroy_gnat_utils): Do not call
invalidate_global_nonconstant_renamings.
(record_global_nonconstant_renaming): Delete.
(invalidate_global_nonconstant_renamings): Likewise.
* gcc-interface/utils2.c (call_is_atomic_load): Move to gigi.h.
(build_load_modify_store): Build a copy of the destination.
(gnat_stabilize_reference_1): Adjust.
(gnat_stabilize_reference): Call gnat_stabilize_reference_1 through
gnat_rewrite_reference and move bulk of code to...
(gnat_rewrite_reference): ...here. New global function.
(gnat_constant_reference_p): Delete.
2015-05-26 Eric Botcazou <ebotcazou@adacore.com>
* gcc-interface/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 * gcc-interface/decl.c (gnat_to_gnu_entity): Do not rely on const_flag
to detect constant renamings. Be prepared for specific pattern of to detect constant renamings. Be prepared for specific pattern of
......
...@@ -394,10 +394,6 @@ do { \ ...@@ -394,10 +394,6 @@ do { \
is readonly. */ is readonly. */
#define DECL_POINTS_TO_READONLY_P(NODE) DECL_LANG_FLAG_4 (NODE) #define DECL_POINTS_TO_READONLY_P(NODE) DECL_LANG_FLAG_4 (NODE)
/* Nonzero in a VAR_DECL if it is a global non-constant renaming. */
#define DECL_GLOBAL_NONCONSTANT_RENAMING_P(NODE) \
DECL_LANG_FLAG_5 (VAR_DECL_CHECK (NODE))
/* In a FIELD_DECL corresponding to a discriminant, contains the /* In a FIELD_DECL corresponding to a discriminant, contains the
discriminant number. */ discriminant number. */
#define DECL_DISCRIMINANT_NUMBER(NODE) DECL_INITIAL (FIELD_DECL_CHECK (NODE)) #define DECL_DISCRIMINANT_NUMBER(NODE) DECL_INITIAL (FIELD_DECL_CHECK (NODE))
...@@ -439,8 +435,7 @@ do { \ ...@@ -439,8 +435,7 @@ do { \
SET_DECL_LANG_SPECIFIC (VAR_DECL_CHECK (NODE), X) SET_DECL_LANG_SPECIFIC (VAR_DECL_CHECK (NODE), X)
/* In a VAR_DECL without the DECL_LOOP_PARM_P flag set and that is a renaming /* In a VAR_DECL without the DECL_LOOP_PARM_P flag set and that is a renaming
pointer, points to the object being renamed, if any. Note that this object pointer, points to the object being renamed, if any. */
is guaranteed to be protected against multiple evaluations. */
#define DECL_RENAMED_OBJECT(NODE) \ #define DECL_RENAMED_OBJECT(NODE) \
GET_DECL_LANG_SPECIFIC (VAR_DECL_CHECK (NODE)) GET_DECL_LANG_SPECIFIC (VAR_DECL_CHECK (NODE))
#define SET_DECL_RENAMED_OBJECT(NODE, X) \ #define SET_DECL_RENAMED_OBJECT(NODE, X) \
......
...@@ -179,6 +179,7 @@ static bool type_has_variable_size (tree); ...@@ -179,6 +179,7 @@ static bool type_has_variable_size (tree);
static tree elaborate_expression_1 (tree, Entity_Id, const char *, bool, bool); static tree elaborate_expression_1 (tree, Entity_Id, const char *, bool, bool);
static tree elaborate_expression_2 (tree, Entity_Id, const char *, bool, bool, static tree elaborate_expression_2 (tree, Entity_Id, const char *, bool, bool,
unsigned int); unsigned int);
static tree elaborate_reference (tree, Entity_Id, bool);
static tree gnat_to_gnu_component_type (Entity_Id, bool, bool); static tree gnat_to_gnu_component_type (Entity_Id, bool, bool);
static tree gnat_to_gnu_param (Entity_Id, Mechanism_Type, Entity_Id, bool, static tree gnat_to_gnu_param (Entity_Id, Mechanism_Type, Entity_Id, bool,
bool *); bool *);
...@@ -557,11 +558,11 @@ gnat_to_gnu_entity (Entity_Id gnat_entity, tree gnu_expr, int definition) ...@@ -557,11 +558,11 @@ gnat_to_gnu_entity (Entity_Id gnat_entity, tree gnu_expr, int definition)
break; break;
} }
/* If we have an external constant that we are not defining, get the /* If we have a constant that we are not defining, get the expression it
expression that is was defined to represent. We may throw it away was defined to represent. This is necessary to avoid generating dumb
later if it is not a constant. But do not retrieve the expression elaboration code in simple cases, but we may throw it away later if it
if it is an allocator because the designated type might be dummy is not a constant. But do not retrieve it if it is an allocator since
at this point. */ the designated type might still be dummy at this point. */
if (!definition if (!definition
&& !No_Initialization (Declaration_Node (gnat_entity)) && !No_Initialization (Declaration_Node (gnat_entity))
&& Present (Expression (Declaration_Node (gnat_entity))) && Present (Expression (Declaration_Node (gnat_entity)))
...@@ -995,32 +996,31 @@ gnat_to_gnu_entity (Entity_Id gnat_entity, tree gnu_expr, int definition) ...@@ -995,32 +996,31 @@ gnat_to_gnu_entity (Entity_Id gnat_entity, tree gnu_expr, int definition)
before the call to "=". */ before the call to "=". */
if (TREE_CODE (inner) == TRUTH_ANDIF_EXPR) if (TREE_CODE (inner) == TRUTH_ANDIF_EXPR)
inner = TREE_OPERAND (inner, 1); inner = TREE_OPERAND (inner, 1);
if (TREE_CODE (inner) == CALL_EXPR if ((TREE_CODE (inner) == CALL_EXPR
|| TREE_CODE (inner) == NULL_EXPR && !call_is_atomic_load (inner))
|| TREE_CODE (inner) == CONSTRUCTOR || TREE_CODE (inner) == NULL_EXPR
|| TREE_CODE (inner) == CONSTRUCTOR
|| CONSTANT_CLASS_P (inner)) || CONSTANT_CLASS_P (inner))
; ;
/* Case 2: if the renaming entity need not be materialized, use /* Case 2: if the renaming entity need not be materialized, use
the stabilized renamed expression for the renaming. At the the elaborated renamed expression for the renaming. But this
global level, we can do this only if we know no SAVE_EXPRs means that the caller is responsible for evaluating the address
need be made, because otherwise the expression would be tied of the renaming at the correct spot in the definition case to
to a specific elaboration routine. */ instantiate the SAVE_EXPRs. */
else if (!Materialize_Entity (gnat_entity) else if (!Materialize_Entity (gnat_entity))
&& (!global_bindings_p ()
|| (staticp (gnu_expr)
&& !TREE_SIDE_EFFECTS (gnu_expr))))
{ {
gnu_decl = gnat_stabilize_reference (gnu_expr, true); gnu_decl
= elaborate_reference (gnu_expr, gnat_entity, definition);
/* ??? No DECL_EXPR is created so we need to mark /* No DECL_EXPR will be created so the expression needs to be
the expression manually lest it is shared. */ marked manually because it will likely be shared. */
if (global_bindings_p ()) if (global_bindings_p ())
MARK_VISITED (gnu_decl); MARK_VISITED (gnu_decl);
/* This assertion will fail if the renamed object isn't /* This assertion will fail if the renamed object isn't aligned
aligned enough as to make it possible to honor the enough as to make it possible to honor the alignment set on
alignment set on the renaming. */ the renaming. */
if (align) if (align)
{ {
unsigned int ralign = DECL_P (gnu_decl) unsigned int ralign = DECL_P (gnu_decl)
...@@ -1036,52 +1036,41 @@ gnat_to_gnu_entity (Entity_Id gnat_entity, tree gnu_expr, int definition) ...@@ -1036,52 +1036,41 @@ gnat_to_gnu_entity (Entity_Id gnat_entity, tree gnu_expr, int definition)
} }
/* Case 3: otherwise, make 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 after it are renaming and attach the object to the pointer after it is
is stabilized. elaborated. The object will be referenced directly instead
of indirectly via the pointer to avoid aliasing problems with
From the proper scope, attached objects will be referenced non-addressable entities. The pointer is called a "renaming"
directly instead of indirectly via the pointer to avoid pointer in this case. Note that we also need to preserve the
subtle aliasing problems with non-addressable entities. volatility of the renamed object through the indirection. */
They have to be stable because we must not evaluate the
variables in the expression every time the renaming is used.
The pointer is called a "renaming" pointer in this case.
Note that we need to preserve the volatility of the renamed
object through the indirection. */
else 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);
gnu_type = build_reference_type (gnu_type); gnu_type = build_reference_type (gnu_type);
inner_const_flag = TREE_READONLY (gnu_expr); used_by_ref = true;
const_flag = true; const_flag = true;
inner_const_flag = TREE_READONLY (gnu_expr);
gnu_size = NULL_TREE;
/* Stabilize and attach the expression to the pointer. renamed_obj
= elaborate_reference (gnu_expr, gnat_entity, definition);
Note that this might introduce SAVE_EXPRs and we don't
check whether we are at the global level or not. This
is fine since we are building a pointer initializer and
neither the pointer nor the initializing expression can
be accessed before the pointer elaboration has taken
place in a correct program.
These SAVE_EXPRs will be evaluated at the right place /* If we are not defining the entity, the expression will not
by either the evaluation of the initializer for the be attached through DECL_INITIAL so it needs to be marked
non-global case or the elaboration code for the global manually because it will likely be shared. Likewise for a
case, and will be attached to the elaboration procedure dereference as it will be folded by the ADDR_EXPR below. */
in the latter case. */ if ((!definition || TREE_CODE (renamed_obj) == INDIRECT_REF)
renamed_obj = gnat_stabilize_reference (gnu_expr, true); && global_bindings_p ())
MARK_VISITED (renamed_obj);
if (type_annotate_only if (type_annotate_only
&& TREE_CODE (renamed_obj) == 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, renamed_obj); = build_unary_op (ADDR_EXPR, gnu_type, renamed_obj);
gnu_size = NULL_TREE;
used_by_ref = true;
} }
} }
...@@ -1173,9 +1162,6 @@ gnat_to_gnu_entity (Entity_Id gnat_entity, tree gnu_expr, int definition) ...@@ -1173,9 +1162,6 @@ gnat_to_gnu_entity (Entity_Id gnat_entity, tree gnu_expr, int definition)
save_gnu_tree (gnat_entity, NULL_TREE, false); save_gnu_tree (gnat_entity, NULL_TREE, false);
/* Ignore the size. It's either meaningless or was handled
above. */
gnu_size = NULL_TREE;
/* Convert the type of the object to a reference type that can /* Convert the type of the object to a reference type that can
alias everything as per 13.3(19). */ alias everything as per 13.3(19). */
gnu_type gnu_type
...@@ -1185,6 +1171,7 @@ gnat_to_gnu_entity (Entity_Id gnat_entity, tree gnu_expr, int definition) ...@@ -1185,6 +1171,7 @@ gnat_to_gnu_entity (Entity_Id gnat_entity, tree gnu_expr, int definition)
const_flag const_flag
= !Is_Public (gnat_entity) = !Is_Public (gnat_entity)
|| compile_time_known_address_p (gnat_expr); || compile_time_known_address_p (gnat_expr);
gnu_size = NULL_TREE;
/* If this is a deferred constant, the initializer is attached to /* If this is a deferred constant, the initializer is attached to
the full view. */ the full view. */
...@@ -1221,6 +1208,7 @@ gnat_to_gnu_entity (Entity_Id gnat_entity, tree gnu_expr, int definition) ...@@ -1221,6 +1208,7 @@ gnat_to_gnu_entity (Entity_Id gnat_entity, tree gnu_expr, int definition)
alias everything as per 13.3(19). */ alias everything as per 13.3(19). */
gnu_type gnu_type
= build_reference_type_for_mode (gnu_type, ptr_mode, true); = build_reference_type_for_mode (gnu_type, ptr_mode, true);
used_by_ref = true;
gnu_size = NULL_TREE; gnu_size = NULL_TREE;
/* No point in taking the address of an initializing expression /* No point in taking the address of an initializing expression
...@@ -1241,8 +1229,6 @@ gnat_to_gnu_entity (Entity_Id gnat_entity, tree gnu_expr, int definition) ...@@ -1241,8 +1229,6 @@ gnat_to_gnu_entity (Entity_Id gnat_entity, tree gnu_expr, int definition)
const_flag = true; const_flag = true;
} }
} }
used_by_ref = true;
} }
/* If we are at top level and this object is of variable size, /* If we are at top level and this object is of variable size,
...@@ -1269,8 +1255,9 @@ gnat_to_gnu_entity (Entity_Id gnat_entity, tree gnu_expr, int definition) ...@@ -1269,8 +1255,9 @@ gnat_to_gnu_entity (Entity_Id gnat_entity, tree gnu_expr, int definition)
|| static_p))) || static_p)))
{ {
gnu_type = build_reference_type (gnu_type); gnu_type = build_reference_type (gnu_type);
gnu_size = NULL_TREE;
used_by_ref = true; used_by_ref = true;
const_flag = true;
gnu_size = NULL_TREE;
/* In case this was a aliased object whose nominal subtype is /* In case this was a aliased object whose nominal subtype is
unconstrained, the pointer above will be a thin pointer and unconstrained, the pointer above will be a thin pointer and
...@@ -1313,13 +1300,9 @@ gnat_to_gnu_entity (Entity_Id gnat_entity, tree gnu_expr, int definition) ...@@ -1313,13 +1300,9 @@ gnat_to_gnu_entity (Entity_Id gnat_entity, tree gnu_expr, int definition)
gnu_expr gnu_expr
= build_allocator (gnu_alloc_type, gnu_expr, gnu_type, = build_allocator (gnu_alloc_type, gnu_expr, gnu_type,
Empty, Empty, gnat_entity, mutable_p); Empty, Empty, gnat_entity, mutable_p);
const_flag = true;
} }
else else
{ gnu_expr = NULL_TREE;
gnu_expr = NULL_TREE;
const_flag = false;
}
} }
/* If this object would go into the stack and has an alignment larger /* If this object would go into the stack and has an alignment larger
...@@ -1357,9 +1340,9 @@ gnat_to_gnu_entity (Entity_Id gnat_entity, tree gnu_expr, int definition) ...@@ -1357,9 +1340,9 @@ gnat_to_gnu_entity (Entity_Id gnat_entity, tree gnu_expr, int definition)
build_component_ref (gnu_new_var, NULL_TREE, build_component_ref (gnu_new_var, NULL_TREE,
TYPE_FIELDS (gnu_new_type), false)); TYPE_FIELDS (gnu_new_type), false));
gnu_size = NULL_TREE;
used_by_ref = true; used_by_ref = true;
const_flag = true; const_flag = true;
gnu_size = NULL_TREE;
} }
/* If this is an aliased object with an unconstrained nominal subtype, /* If this is an aliased object with an unconstrained nominal subtype,
...@@ -1389,10 +1372,10 @@ gnat_to_gnu_entity (Entity_Id gnat_entity, tree gnu_expr, int definition) ...@@ -1389,10 +1372,10 @@ gnat_to_gnu_entity (Entity_Id gnat_entity, tree gnu_expr, int definition)
= build_unary_op (ADDR_EXPR, NULL_TREE, gnu_unc_var); = build_unary_op (ADDR_EXPR, NULL_TREE, gnu_unc_var);
TREE_CONSTANT (gnu_expr) = 1; TREE_CONSTANT (gnu_expr) = 1;
gnu_size = NULL_TREE;
used_by_ref = true; used_by_ref = true;
inner_const_flag = TREE_READONLY (gnu_unc_var);
const_flag = true; const_flag = true;
inner_const_flag = TREE_READONLY (gnu_unc_var);
gnu_size = NULL_TREE;
} }
gnu_type gnu_type
...@@ -1481,20 +1464,9 @@ gnat_to_gnu_entity (Entity_Id gnat_entity, tree gnu_expr, int definition) ...@@ -1481,20 +1464,9 @@ gnat_to_gnu_entity (Entity_Id gnat_entity, tree gnu_expr, int definition)
else if (kind == E_Loop_Parameter) else if (kind == E_Loop_Parameter)
DECL_LOOP_PARM_P (gnu_decl) = 1; DECL_LOOP_PARM_P (gnu_decl) = 1;
/* 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. */
register it if we are at the global level and the renamed object
is a non-constant reference. */
if (renamed_obj) if (renamed_obj)
{ SET_DECL_RENAMED_OBJECT (gnu_decl, renamed_obj);
SET_DECL_RENAMED_OBJECT (gnu_decl, renamed_obj);
if (global_bindings_p ()
&& !gnat_constant_reference_p (renamed_obj))
{
DECL_GLOBAL_NONCONSTANT_RENAMING_P (gnu_decl) = 1;
record_global_nonconstant_renaming (gnu_decl);
}
}
/* If this is a constant and we are defining it or it generates a real /* If this is a constant and we are defining it or it generates a real
symbol at the object level and we are referencing it, we may want symbol at the object level and we are referencing it, we may want
...@@ -6109,7 +6081,7 @@ prepend_attributes (struct attrib **attr_list, Entity_Id gnat_entity) ...@@ -6109,7 +6081,7 @@ prepend_attributes (struct attrib **attr_list, Entity_Id gnat_entity)
/* Given a GNAT tree GNAT_EXPR, for an expression which is a value within a /* Given a GNAT tree GNAT_EXPR, for an expression which is a value within a
type definition (either a bound or a discriminant value) for GNAT_ENTITY, type definition (either a bound or a discriminant value) for GNAT_ENTITY,
return the GCC tree to use for that expression. S is the suffix to use return the GCC tree to use for that expression. S is the suffix to use
if a variable needs to be created and DEFINITION is true if this is made if a variable needs to be created and DEFINITION is true if this is done
for a definition of GNAT_ENTITY. If NEED_VALUE is true, we need a result; for a definition of GNAT_ENTITY. If NEED_VALUE is true, we need a result;
otherwise, we are just elaborating the expression for side-effects. If otherwise, we are just elaborating the expression for side-effects. If
NEED_DEBUG is true, we need a variable for debugging purposes even if it NEED_DEBUG is true, we need a variable for debugging purposes even if it
...@@ -6250,6 +6222,50 @@ elaborate_expression_2 (tree gnu_expr, Entity_Id gnat_entity, const char *s, ...@@ -6250,6 +6222,50 @@ elaborate_expression_2 (tree gnu_expr, Entity_Id gnat_entity, const char *s,
need_debug), need_debug),
unit_align); unit_align);
} }
/* Structure to hold internal data for elaborate_reference. */
struct er_data
{
Entity_Id entity;
bool definition;
};
/* Wrapper function around elaborate_expression_1 for elaborate_reference. */
static tree
elaborate_reference_1 (tree ref, void *data, int n)
{
struct er_data *er = (struct er_data *)data;
char suffix[16];
/* This is what elaborate_expression_1 does if NEED_DEBUG is false. */
if (TREE_CONSTANT (ref))
return ref;
/* If this is a COMPONENT_REF of a fat pointer, elaborate the entire fat
pointer. This may be more efficient, but will also allow us to more
easily find the match for the PLACEHOLDER_EXPR. */
if (TREE_CODE (ref) == COMPONENT_REF
&& TYPE_IS_FAT_POINTER_P (TREE_TYPE (TREE_OPERAND (ref, 0))))
return build3 (COMPONENT_REF, TREE_TYPE (ref),
elaborate_reference_1 (TREE_OPERAND (ref, 0), data, n),
TREE_OPERAND (ref, 1), TREE_OPERAND (ref, 2));
sprintf (suffix, "EXP%d", n);
return
elaborate_expression_1 (ref, er->entity, suffix, er->definition, false);
}
/* Elaborate the reference REF to be used as renamed object for GNAT_ENTITY.
DEFINITION is true if this is done for a definition of GNAT_ENTITY. */
static tree
elaborate_reference (tree ref, Entity_Id gnat_entity, bool definition)
{
struct er_data er = { gnat_entity, definition };
return gnat_rewrite_reference (ref, elaborate_reference_1, &er);
}
/* Given a GNU tree and a GNAT list of choices, generate an expression to test /* Given a GNU tree and a GNAT list of choices, generate an expression to test
the value passed against the list of choices. */ the value passed against the list of choices. */
......
...@@ -712,12 +712,6 @@ create_var_decl_1 (tree var_name, tree asm_name, tree type, tree var_init, ...@@ -712,12 +712,6 @@ create_var_decl_1 (tree var_name, tree asm_name, tree type, tree var_init,
const_flag, public_flag, extern_flag, \ const_flag, public_flag, extern_flag, \
static_flag, false, attr_list, gnat_node) static_flag, false, attr_list, gnat_node)
/* Record DECL as a global non-constant renaming. */
extern void record_global_nonconstant_renaming (tree decl);
/* Invalidate the global non-constant renamings. */
extern void invalidate_global_nonconstant_renamings (void);
/* Return a FIELD_DECL node. FIELD_NAME is the field's name, FIELD_TYPE is /* Return a FIELD_DECL node. FIELD_NAME is the field's name, FIELD_TYPE is
its type and RECORD_TYPE is the type of the enclosing record. If SIZE is its type and RECORD_TYPE is the type of the enclosing record. If SIZE is
nonzero, it is the specified size of the field. If POS is nonzero, it is nonzero, it is the specified size of the field. If POS is nonzero, it is
...@@ -968,15 +962,19 @@ extern tree gnat_protect_expr (tree exp); ...@@ -968,15 +962,19 @@ extern tree gnat_protect_expr (tree exp);
force evaluation of everything. */ force evaluation of everything. */
extern tree gnat_stabilize_reference (tree ref, bool force); extern tree gnat_stabilize_reference (tree ref, bool force);
/* Rewrite reference REF and call FUNC on each expression within REF in the
process. DATA is passed unmodified to FUNC and N is bumped each time it
is passed to FUNC, so FUNC is guaranteed to see a given N only once per
reference to be rewritten. */
typedef tree (*rewrite_fn) (tree, void *, int);
extern tree gnat_rewrite_reference (tree ref, rewrite_fn func, void *data,
int n = 1);
/* 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,
i.e. if it doesn't depend on the context in which it is evaluated. */ i.e. if it doesn't depend on the context in which it is evaluated. */
extern tree get_inner_constant_reference (tree exp); extern tree get_inner_constant_reference (tree exp);
/* Return true if REF is a constant reference, i.e. a reference (lvalue) that
doesn't depend on the context in which it is evaluated. */
extern bool gnat_constant_reference_p (tree ref);
/* If EXPR is an expression that is invariant in the current function, in the /* If EXPR is an expression that is invariant in the current function, in the
sense that it can be evaluated anywhere in the function and any number of sense that it can be evaluated anywhere in the function and any number of
times, return EXPR or an equivalent expression. Otherwise return NULL. */ times, return EXPR or an equivalent expression. Otherwise return NULL. */
...@@ -1073,3 +1071,17 @@ ceil_pow2 (unsigned HOST_WIDE_INT x) ...@@ -1073,3 +1071,17 @@ ceil_pow2 (unsigned HOST_WIDE_INT x)
{ {
return (unsigned HOST_WIDE_INT) 1 << (floor_log2 (x - 1) + 1); return (unsigned HOST_WIDE_INT) 1 << (floor_log2 (x - 1) + 1);
} }
/* Return true if EXP, a CALL_EXPR, is an atomic load. */
static inline bool
call_is_atomic_load (tree exp)
{
tree fndecl = get_callee_fndecl (exp);
if (!(fndecl && DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL))
return false;
enum built_in_function code = DECL_FUNCTION_CODE (fndecl);
return BUILT_IN_ATOMIC_LOAD_N <= code && code <= BUILT_IN_ATOMIC_LOAD_16;
}
...@@ -1163,15 +1163,10 @@ Identifier_to_gnu (Node_Id gnat_node, tree *gnu_result_type_p) ...@@ -1163,15 +1163,10 @@ Identifier_to_gnu (Node_Id gnat_node, tree *gnu_result_type_p)
true, false))) true, false)))
gnu_result = DECL_INITIAL (gnu_result); gnu_result = DECL_INITIAL (gnu_result);
/* If it's a renaming pointer and not a global non-constant renaming or /* If it's a renaming pointer, get to the renamed object. */
we are at the global level, the we can reference the renamed object
directly, since it is either constant or has been protected against
multiple evaluations. */
if (TREE_CODE (gnu_result) == VAR_DECL if (TREE_CODE (gnu_result) == VAR_DECL
&& !DECL_LOOP_PARM_P (gnu_result) && !DECL_LOOP_PARM_P (gnu_result)
&& DECL_RENAMED_OBJECT (gnu_result) && DECL_RENAMED_OBJECT (gnu_result))
&& (!DECL_GLOBAL_NONCONSTANT_RENAMING_P (gnu_result)
|| global_bindings_p ()))
gnu_result = DECL_RENAMED_OBJECT (gnu_result); gnu_result = DECL_RENAMED_OBJECT (gnu_result);
/* Otherwise, do the final dereference. */ /* Otherwise, do the final dereference. */
...@@ -3975,16 +3970,32 @@ outer_atomic_access_required_p (Node_Id gnat_node) ...@@ -3975,16 +3970,32 @@ outer_atomic_access_required_p (Node_Id gnat_node)
{ {
gnat_node = gnat_strip_type_conversion (gnat_node); gnat_node = gnat_strip_type_conversion (gnat_node);
while (Nkind (gnat_node) == N_Indexed_Component while (true)
|| Nkind (gnat_node) == N_Selected_Component
|| Nkind (gnat_node) == N_Slice)
{ {
gnat_node = gnat_strip_type_conversion (Prefix (gnat_node)); switch (Nkind (gnat_node))
if (node_has_volatile_full_access (gnat_node)) {
return true; case N_Identifier:
case N_Expanded_Name:
if (No (Renamed_Object (Entity (gnat_node))))
return false;
gnat_node
= gnat_strip_type_conversion (Renamed_Object (Entity (gnat_node)));
break;
case N_Indexed_Component:
case N_Selected_Component:
case N_Slice:
gnat_node = gnat_strip_type_conversion (Prefix (gnat_node));
if (node_has_volatile_full_access (gnat_node))
return true;
break;
default:
return false;
}
} }
return false; gcc_unreachable ();
} }
/* Return true if GNAT_NODE requires atomic access and set SYNC according to /* Return true if GNAT_NODE requires atomic access and set SYNC according to
...@@ -5290,11 +5301,6 @@ Compilation_Unit_to_gnu (Node_Id gnat_node) ...@@ -5290,11 +5301,6 @@ Compilation_Unit_to_gnu (Node_Id gnat_node)
info->gnat_node = gnat_node; info->gnat_node = gnat_node;
elab_info_list = info; elab_info_list = info;
/* Invalidate the global non-constant renamings. This is necessary because
stabilization of the renamed entities may create SAVE_EXPRs which have
been tied to a specific elaboration routine just above. */
invalidate_global_nonconstant_renamings ();
/* Force the processing for all nodes that remain in the queue. */ /* Force the processing for all nodes that remain in the queue. */
process_deferred_decl_context (true); process_deferred_decl_context (true);
} }
...@@ -5838,8 +5844,7 @@ gnat_to_gnu (Node_Id gnat_node) ...@@ -5838,8 +5844,7 @@ gnat_to_gnu (Node_Id gnat_node)
tree gnu_temp tree gnu_temp
= gnat_to_gnu_entity (gnat_temp, = gnat_to_gnu_entity (gnat_temp,
gnat_to_gnu (Renamed_Object (gnat_temp)), 1); gnat_to_gnu (Renamed_Object (gnat_temp)), 1);
/* We need to make sure that the side-effects of the renamed object /* See case 2 of renaming in gnat_to_gnu_entity. */
are evaluated at this point, so we evaluate its address. */
if (TREE_SIDE_EFFECTS (gnu_temp)) if (TREE_SIDE_EFFECTS (gnu_temp))
gnu_result = build_unary_op (ADDR_EXPR, NULL_TREE, gnu_temp); gnu_result = build_unary_op (ADDR_EXPR, NULL_TREE, gnu_temp);
} }
...@@ -7933,6 +7938,26 @@ gnat_gimplify_expr (tree *expr_p, gimple_seq *pre_p, ...@@ -7933,6 +7938,26 @@ gnat_gimplify_expr (tree *expr_p, gimple_seq *pre_p,
return GS_ALL_DONE; return GS_ALL_DONE;
} }
/* Replace atomic loads with their first argument. That's necessary
because the gimplifier would create a temporary otherwise. */
if (TREE_SIDE_EFFECTS (op))
while (handled_component_p (op) || CONVERT_EXPR_P (op))
{
tree inner = TREE_OPERAND (op, 0);
if (TREE_CODE (inner) == CALL_EXPR && call_is_atomic_load (inner))
{
tree t = CALL_EXPR_ARG (inner, 0);
if (TREE_CODE (t) == NOP_EXPR)
t = TREE_OPERAND (t, 0);
if (TREE_CODE (t) == ADDR_EXPR)
TREE_OPERAND (op, 0) = TREE_OPERAND (t, 0);
else
TREE_OPERAND (op, 0) = build_fold_indirect_ref (t);
}
else
op = inner;
}
return GS_UNHANDLED; return GS_UNHANDLED;
case VIEW_CONVERT_EXPR: case VIEW_CONVERT_EXPR:
......
...@@ -233,9 +233,6 @@ static GTY(()) vec<tree, va_gc> *global_decls; ...@@ -233,9 +233,6 @@ static GTY(()) vec<tree, va_gc> *global_decls;
/* An array of builtin function declarations. */ /* An array of builtin function declarations. */
static GTY(()) vec<tree, va_gc> *builtin_decls; static GTY(()) vec<tree, va_gc> *builtin_decls;
/* An array of global non-constant renamings. */
static GTY(()) vec<tree, va_gc> *global_nonconstant_renamings;
/* A chain of unused BLOCK nodes. */ /* A chain of unused BLOCK nodes. */
static GTY((deletable)) tree free_block_chain; static GTY((deletable)) tree free_block_chain;
...@@ -322,9 +319,6 @@ destroy_gnat_utils (void) ...@@ -322,9 +319,6 @@ destroy_gnat_utils (void)
/* Destroy the hash table of padded types. */ /* Destroy the hash table of padded types. */
pad_type_hash_table->empty (); pad_type_hash_table->empty ();
pad_type_hash_table = NULL; pad_type_hash_table = NULL;
/* Invalidate the global non-constant renamings. */
invalidate_global_nonconstant_renamings ();
} }
/* GNAT_ENTITY is a GNAT tree node for an entity. Associate GNU_DECL, a GCC /* GNAT_ENTITY is a GNAT tree node for an entity. Associate GNU_DECL, a GCC
...@@ -2717,33 +2711,6 @@ process_attributes (tree *node, struct attrib **attr_list, bool in_place, ...@@ -2717,33 +2711,6 @@ process_attributes (tree *node, struct attrib **attr_list, bool in_place,
*attr_list = NULL; *attr_list = NULL;
} }
/* Record DECL as a global non-constant renaming. */
void
record_global_nonconstant_renaming (tree decl)
{
gcc_assert (!DECL_LOOP_PARM_P (decl) && DECL_RENAMED_OBJECT (decl));
vec_safe_push (global_nonconstant_renamings, decl);
}
/* Invalidate the global non-constant renamings, lest their renamed object
contains SAVE_EXPRs tied to an elaboration routine. */
void
invalidate_global_nonconstant_renamings (void)
{
unsigned int i;
tree iter;
if (global_nonconstant_renamings == NULL)
return;
FOR_EACH_VEC_ELT (*global_nonconstant_renamings, i, iter)
SET_DECL_RENAMED_OBJECT (iter, NULL_TREE);
vec_free (global_nonconstant_renamings);
}
/* Return true if VALUE is a known to be a multiple of FACTOR, which must be /* Return true if VALUE is a known to be a multiple of FACTOR, which must be
a power of 2. */ a power of 2. */
......
...@@ -738,27 +738,15 @@ build_atomic_store (tree dest, tree src, bool sync) ...@@ -738,27 +738,15 @@ build_atomic_store (tree dest, tree src, bool sync)
return build_call_expr (t, 3, addr, src, mem_model); return build_call_expr (t, 3, addr, src, mem_model);
} }
/* Return true if EXP, a CALL_EXPR, is an atomic load. */
static bool
call_is_atomic_load (tree exp)
{
tree fndecl = get_callee_fndecl (exp);
if (!(fndecl && DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL))
return false;
enum built_in_function code = DECL_FUNCTION_CODE (fndecl);
return BUILT_IN_ATOMIC_LOAD_N <= code && code <= BUILT_IN_ATOMIC_LOAD_16;
}
/* Build a load-modify-store sequence from SRC to DEST. GNAT_NODE is used for /* Build a load-modify-store sequence from SRC to DEST. GNAT_NODE is used for
the location of the sequence. Note that, even if the load and the store are the location of the sequence. Note that, even though the load and the store
both atomic, the sequence itself is not atomic. */ are both atomic, the sequence itself is not atomic. */
tree tree
build_load_modify_store (tree dest, tree src, Node_Id gnat_node) build_load_modify_store (tree dest, tree src, Node_Id gnat_node)
{ {
/* We will be modifying DEST below so we build a copy. */
dest = copy_node (dest);
tree ref = dest; tree ref = dest;
while (handled_component_p (ref)) while (handled_component_p (ref))
...@@ -812,6 +800,7 @@ build_load_modify_store (tree dest, tree src, Node_Id gnat_node) ...@@ -812,6 +800,7 @@ build_load_modify_store (tree dest, tree src, Node_Id gnat_node)
} }
} }
TREE_OPERAND (ref, 0) = copy_node (TREE_OPERAND (ref, 0));
ref = TREE_OPERAND (ref, 0); ref = TREE_OPERAND (ref, 0);
} }
...@@ -2674,8 +2663,9 @@ gnat_protect_expr (tree exp) ...@@ -2674,8 +2663,9 @@ gnat_protect_expr (tree exp)
argument to force evaluation of everything. */ argument to force evaluation of everything. */
static tree static tree
gnat_stabilize_reference_1 (tree e, bool force) gnat_stabilize_reference_1 (tree e, void *data, int n)
{ {
const bool force = *(bool *)data;
enum tree_code code = TREE_CODE (e); enum tree_code code = TREE_CODE (e);
tree type = TREE_TYPE (e); tree type = TREE_TYPE (e);
tree result; tree result;
...@@ -2698,7 +2688,7 @@ gnat_stabilize_reference_1 (tree e, bool force) ...@@ -2698,7 +2688,7 @@ gnat_stabilize_reference_1 (tree e, bool force)
&& TYPE_IS_FAT_POINTER_P (TREE_TYPE (TREE_OPERAND (e, 0)))) && TYPE_IS_FAT_POINTER_P (TREE_TYPE (TREE_OPERAND (e, 0))))
result result
= build3 (code, type, = build3 (code, type,
gnat_stabilize_reference_1 (TREE_OPERAND (e, 0), force), gnat_stabilize_reference_1 (TREE_OPERAND (e, 0), data, n),
TREE_OPERAND (e, 1), TREE_OPERAND (e, 2)); TREE_OPERAND (e, 1), TREE_OPERAND (e, 2));
/* If the expression has side-effects, then encase it in a SAVE_EXPR /* If the expression has side-effects, then encase it in a SAVE_EXPR
so that it will only be evaluated once. */ so that it will only be evaluated once. */
...@@ -2714,15 +2704,15 @@ gnat_stabilize_reference_1 (tree e, bool force) ...@@ -2714,15 +2704,15 @@ gnat_stabilize_reference_1 (tree e, bool force)
/* Recursively stabilize each operand. */ /* Recursively stabilize each operand. */
result result
= build2 (code, type, = build2 (code, type,
gnat_stabilize_reference_1 (TREE_OPERAND (e, 0), force), gnat_stabilize_reference_1 (TREE_OPERAND (e, 0), data, n),
gnat_stabilize_reference_1 (TREE_OPERAND (e, 1), force)); gnat_stabilize_reference_1 (TREE_OPERAND (e, 1), data, n));
break; break;
case tcc_unary: case tcc_unary:
/* Recursively stabilize each operand. */ /* Recursively stabilize each operand. */
result result
= build1 (code, type, = build1 (code, type,
gnat_stabilize_reference_1 (TREE_OPERAND (e, 0), force)); gnat_stabilize_reference_1 (TREE_OPERAND (e, 0), data, n));
break; break;
default: default:
...@@ -2743,6 +2733,17 @@ gnat_stabilize_reference_1 (tree e, bool force) ...@@ -2743,6 +2733,17 @@ gnat_stabilize_reference_1 (tree e, bool force)
tree tree
gnat_stabilize_reference (tree ref, bool force) gnat_stabilize_reference (tree ref, bool force)
{ {
return gnat_rewrite_reference (ref, gnat_stabilize_reference_1, &force);
}
/* Rewrite reference REF and call FUNC on each expression within REF in the
process. DATA is passed unmodified to FUNC and N is bumped each time it
is passed to FUNC, so FUNC is guaranteed to see a given N only once per
reference to be rewritten. */
tree
gnat_rewrite_reference (tree ref, rewrite_fn func, void *data, int n)
{
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;
...@@ -2762,25 +2763,26 @@ gnat_stabilize_reference (tree ref, bool force) ...@@ -2762,25 +2763,26 @@ gnat_stabilize_reference (tree ref, bool force)
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_rewrite_reference (TREE_OPERAND (ref, 0), func, data,
n));
break; break;
case INDIRECT_REF: case INDIRECT_REF:
case UNCONSTRAINED_ARRAY_REF: case UNCONSTRAINED_ARRAY_REF:
result = build1 (code, type, result = build1 (code, type, func (TREE_OPERAND (ref, 0), data, n));
gnat_stabilize_reference_1 (TREE_OPERAND (ref, 0),
force));
break; break;
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_rewrite_reference (TREE_OPERAND (ref, 0), func,
data, n),
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_rewrite_reference (TREE_OPERAND (ref, 0), func,
data, n),
TREE_OPERAND (ref, 1), TREE_OPERAND (ref, 2)); TREE_OPERAND (ref, 1), TREE_OPERAND (ref, 2));
break; break;
...@@ -2788,8 +2790,9 @@ gnat_stabilize_reference (tree ref, bool force) ...@@ -2788,8 +2790,9 @@ gnat_stabilize_reference (tree ref, bool force)
case ARRAY_RANGE_REF: case ARRAY_RANGE_REF:
result result
= build4 (code, type, = build4 (code, type,
gnat_stabilize_reference (TREE_OPERAND (ref, 0), force), gnat_rewrite_reference (TREE_OPERAND (ref, 0), func, data,
gnat_stabilize_reference_1 (TREE_OPERAND (ref, 1), force), n + 1),
func (TREE_OPERAND (ref, 1), data, n),
TREE_OPERAND (ref, 2), TREE_OPERAND (ref, 3)); TREE_OPERAND (ref, 2), TREE_OPERAND (ref, 3));
break; break;
...@@ -2804,9 +2807,10 @@ gnat_stabilize_reference (tree ref, bool force) ...@@ -2804,9 +2807,10 @@ gnat_stabilize_reference (tree ref, bool force)
t = TREE_OPERAND (t, 0); t = TREE_OPERAND (t, 0);
if (TREE_CODE (t) == ADDR_EXPR) if (TREE_CODE (t) == ADDR_EXPR)
t = build1 (ADDR_EXPR, TREE_TYPE (t), t = build1 (ADDR_EXPR, TREE_TYPE (t),
gnat_stabilize_reference (TREE_OPERAND (t, 0), force)); gnat_rewrite_reference (TREE_OPERAND (t, 0), func, data,
n));
else else
t = gnat_stabilize_reference_1 (t, force); t = func (t, data, n);
t = fold_convert (TREE_TYPE (CALL_EXPR_ARG (ref, 0)), t); t = fold_convert (TREE_TYPE (CALL_EXPR_ARG (ref, 0)), t);
result = build_call_expr (TREE_OPERAND (CALL_EXPR_FN (ref), 0), 2, result = build_call_expr (TREE_OPERAND (CALL_EXPR_FN (ref), 0), 2,
...@@ -2895,22 +2899,6 @@ done: ...@@ -2895,22 +2899,6 @@ done:
return exp; return exp;
} }
/* Return true if REF is a constant reference, i.e. a reference (lvalue) that
doesn't depend on the context in which it is evaluated. */
bool
gnat_constant_reference_p (tree ref)
{
if (handled_component_p (ref))
{
ref = get_inner_constant_reference (ref);
if (!ref)
return false;
}
return DECL_P (ref);
}
/* If EXPR is an expression that is invariant in the current function, in the /* If EXPR is an expression that is invariant in the current function, in the
sense that it can be evaluated anywhere in the function and any number of sense that it can be evaluated anywhere in the function and any number of
times, return EXPR or an equivalent expression. Otherwise return NULL. */ times, return EXPR or an equivalent expression. Otherwise return NULL. */
......
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