Commit 3ce5f966 by Olivier Hainque Committed by Arnaud Charlet

trans.c (call_to_gnu): Return an expression with a COMPOUND_EXPR including the call instead of...

2007-04-06  Olivier Hainque  <hainque@adacore.com>
	    Eric Botcazou <botcazou@adacore.com>

	* trans.c (call_to_gnu) <TYPE_RETURNS_BY_TARGET_PTR_P>: Return an
	expression with a COMPOUND_EXPR including the call instead of emitting
	the call directly here.
	(gnat_to_gnu) <N_Slice>: Do not return a non-constant low bound if the
	high bound is constant and the slice is empty.  Tidy.
	(tree_transform, case N_Op_Not): Handle properly the case where the
	operation applies to a private type whose full view is a modular type.
	(Case_Statement_To_gnu): If an alternative is an E_Constant with an
	Address_Clause, use the associated Expression as the GNAT tree
	representing the choice value to ensure the corresponding GCC tree is
	of the proper kind.
	(maybe_stabilize_reference): Stabilize COMPOUND_EXPRs as a whole
	instead of just the operands, as the base GCC stabilize_reference does.
	<CALL_EXPR>: New case. Directly stabilize the call if an lvalue is not
	requested; otherwise fail.
	(addressable_p) <COMPONENT_REF>: Do not test DECL_NONADDRESSABLE_P.

From-SVN: r123608
parent 4b437c6b
...@@ -288,7 +288,7 @@ gigi (Node_Id gnat_root, int max_gnat_node, int number_name, ...@@ -288,7 +288,7 @@ gigi (Node_Id gnat_root, int max_gnat_node, int number_name,
/* Perform initializations for this module. */ /* Perform initializations for this module. */
void void
gnat_init_stmt_group () gnat_init_stmt_group (void)
{ {
/* Initialize ourselves. */ /* Initialize ourselves. */
init_code_table (); init_code_table ();
...@@ -1172,8 +1172,7 @@ Case_Statement_to_gnu (Node_Id gnat_node) ...@@ -1172,8 +1172,7 @@ Case_Statement_to_gnu (Node_Id gnat_node)
case N_Identifier: case N_Identifier:
case N_Expanded_Name: case N_Expanded_Name:
/* This represents either a subtype range or a static value of /* This represents either a subtype range or a static value of
some kind; Ekind says which. If a static value, fall through some kind; Ekind says which. */
to the next case. */
if (IN (Ekind (Entity (gnat_choice)), Type_Kind)) if (IN (Ekind (Entity (gnat_choice)), Type_Kind))
{ {
tree gnu_type = get_unpadded_type (Entity (gnat_choice)); tree gnu_type = get_unpadded_type (Entity (gnat_choice));
...@@ -1182,6 +1181,29 @@ Case_Statement_to_gnu (Node_Id gnat_node) ...@@ -1182,6 +1181,29 @@ Case_Statement_to_gnu (Node_Id gnat_node)
gnu_high = fold (TYPE_MAX_VALUE (gnu_type)); gnu_high = fold (TYPE_MAX_VALUE (gnu_type));
break; break;
} }
/* Static values are handled by the next case to which we'll
fallthrough. If this is a constant with an address clause
attached, we need to get to the initialization expression
first, as the GCC tree for the entity might happen to be an
INDIRECT_REF otherwise. */
else if (Ekind (Entity (gnat_choice)) == E_Constant
&& Present (Address_Clause (Entity (gnat_choice))))
{
/* We might have a deferred constant with an address clause
on either the incomplete or the full view. While the
Address_Clause is always attached to the visible entity,
as tested above, the static value is the Expression
attached to the the declaration of the entity or of its
full view if any. */
Entity_Id gnat_constant = Entity (gnat_choice);
if (Present (Full_View (gnat_constant)))
gnat_constant = Full_View (gnat_constant);
gnat_choice
= Expression (Declaration_Node (gnat_constant));
}
/* ... fall through ... */ /* ... fall through ... */
...@@ -1996,14 +2018,43 @@ call_to_gnu (Node_Id gnat_node, tree *gnu_result_type_p, tree gnu_target) ...@@ -1996,14 +2018,43 @@ call_to_gnu (Node_Id gnat_node, tree *gnu_result_type_p, tree gnu_target)
gnu_subprog_addr, gnu_subprog_addr,
nreverse (gnu_actual_list)); nreverse (gnu_actual_list));
/* If we return by passing a target, we emit the call and return the target /* If we return by passing a target, the result is the target after the
as our result. */ call. We must not emit the call directly here because this might be
evaluated as part of an expression with conditions to control whether
the call should be emitted or not. */
if (TYPE_RETURNS_BY_TARGET_PTR_P (gnu_subprog_type)) if (TYPE_RETURNS_BY_TARGET_PTR_P (gnu_subprog_type))
{ {
add_stmt_with_node (gnu_subprog_call, gnat_node); /* Conceptually, what we need is a COMPOUND_EXPR with the call followed
*gnu_result_type_p by the target object converted to the proper type. Doing so would
potentially be very inefficient, however, as this expresssion might
end up wrapped into an outer SAVE_EXPR later on, which would incur a
pointless temporary copy of the whole object.
What we do instead is build a COMPOUND_EXPR returning the address of
the target, and then dereference. Wrapping the COMPOUND_EXPR into a
SAVE_EXPR later on then only incurs a pointer copy. */
tree gnu_result_type
= TREE_TYPE (TREE_VALUE (TYPE_ARG_TYPES (gnu_subprog_type))); = TREE_TYPE (TREE_VALUE (TYPE_ARG_TYPES (gnu_subprog_type)));
return unchecked_convert (*gnu_result_type_p, gnu_target, false);
/* Build and return
(result_type) *[gnu_subprog_call (&gnu_target, ...), &gnu_target] */
tree gnu_target_address
= build_unary_op (ADDR_EXPR, NULL_TREE, gnu_target);
gnu_result
= build2 (COMPOUND_EXPR, TREE_TYPE (gnu_target_address),
gnu_subprog_call, gnu_target_address);
gnu_result
= unchecked_convert (gnu_result_type,
build_unary_op (INDIRECT_REF, NULL_TREE,
gnu_result),
false);
*gnu_result_type_p = gnu_result_type;
return gnu_result;
} }
/* If it is a function call, the result is the call expression unless /* If it is a function call, the result is the call expression unless
...@@ -3032,65 +3083,73 @@ gnat_to_gnu (Node_Id gnat_node) ...@@ -3032,65 +3083,73 @@ gnat_to_gnu (Node_Id gnat_node)
case N_Slice: case N_Slice:
{ {
tree gnu_type; tree gnu_type;
Node_Id gnat_range_node = Discrete_Range (gnat_node); Node_Id gnat_range_node = Discrete_Range (gnat_node);
gnu_result = gnat_to_gnu (Prefix (gnat_node)); gnu_result = gnat_to_gnu (Prefix (gnat_node));
gnu_result_type = get_unpadded_type (Etype (gnat_node)); gnu_result_type = get_unpadded_type (Etype (gnat_node));
/* Do any implicit dereferences of the prefix and do any needed /* Do any implicit dereferences of the prefix and do any needed
range check. */ range check. */
gnu_result = maybe_implicit_deref (gnu_result); gnu_result = maybe_implicit_deref (gnu_result);
gnu_result = maybe_unconstrained_array (gnu_result); gnu_result = maybe_unconstrained_array (gnu_result);
gnu_type = TREE_TYPE (gnu_result); gnu_type = TREE_TYPE (gnu_result);
if (Do_Range_Check (gnat_range_node)) if (Do_Range_Check (gnat_range_node))
{ {
/* Get the bounds of the slice. */ /* Get the bounds of the slice. */
tree gnu_index_type tree gnu_index_type
= TYPE_INDEX_TYPE (TYPE_DOMAIN (gnu_result_type)); = TYPE_INDEX_TYPE (TYPE_DOMAIN (gnu_result_type));
tree gnu_min_expr = TYPE_MIN_VALUE (gnu_index_type); tree gnu_min_expr = TYPE_MIN_VALUE (gnu_index_type);
tree gnu_max_expr = TYPE_MAX_VALUE (gnu_index_type); tree gnu_max_expr = TYPE_MAX_VALUE (gnu_index_type);
tree gnu_expr_l, gnu_expr_h, gnu_expr_type; /* Get the permitted bounds. */
tree gnu_base_index_type
/* Check to see that the minimum slice value is in range */ = TYPE_INDEX_TYPE (TYPE_DOMAIN (gnu_type));
gnu_expr_l tree gnu_base_min_expr = TYPE_MIN_VALUE (gnu_base_index_type);
= emit_index_check tree gnu_base_max_expr = TYPE_MAX_VALUE (gnu_base_index_type);
(gnu_result, gnu_min_expr, tree gnu_expr_l, gnu_expr_h, gnu_expr_type;
TYPE_MIN_VALUE (TYPE_INDEX_TYPE (TYPE_DOMAIN (gnu_type))),
TYPE_MAX_VALUE (TYPE_INDEX_TYPE (TYPE_DOMAIN (gnu_type)))); /* Check to see that the minimum slice value is in range. */
gnu_expr_l = emit_index_check (gnu_result,
/* Check to see that the maximum slice value is in range */ gnu_min_expr,
gnu_expr_h gnu_base_min_expr,
= emit_index_check gnu_base_max_expr);
(gnu_result, gnu_max_expr,
TYPE_MIN_VALUE (TYPE_INDEX_TYPE (TYPE_DOMAIN (gnu_type))), /* Check to see that the maximum slice value is in range. */
TYPE_MAX_VALUE (TYPE_INDEX_TYPE (TYPE_DOMAIN (gnu_type)))); gnu_expr_h = emit_index_check (gnu_result,
gnu_max_expr,
/* Derive a good type to convert everything too */ gnu_base_min_expr,
gnu_expr_type = get_base_type (TREE_TYPE (gnu_expr_l)); gnu_base_max_expr);
/* Build a compound expression that does the range checks */ /* Derive a good type to convert everything to. */
gnu_expr gnu_expr_type = get_base_type (TREE_TYPE (gnu_expr_l));
= build_binary_op (COMPOUND_EXPR, gnu_expr_type,
convert (gnu_expr_type, gnu_expr_h), /* Build a compound expression that does the range checks and
convert (gnu_expr_type, gnu_expr_l)); returns the low bound. */
gnu_expr = build_binary_op (COMPOUND_EXPR, gnu_expr_type,
/* Build a conditional expression that returns the range checks convert (gnu_expr_type, gnu_expr_h),
expression if the slice range is not null (max >= min) or convert (gnu_expr_type, gnu_expr_l));
returns the min if the slice range is null */
gnu_expr /* Build a conditional expression that does the range check and
= fold_build3 (COND_EXPR, gnu_expr_type, returns the low bound if the slice is not empty (max >= min),
build_binary_op (GE_EXPR, gnu_expr_type, and returns the naked low bound otherwise (max < min), unless
convert (gnu_expr_type, it is non-constant and the high bound is; this prevents VRP
gnu_max_expr), from inferring bogus ranges on the unlikely path. */
convert (gnu_expr_type, gnu_expr = fold_build3 (COND_EXPR, gnu_expr_type,
gnu_min_expr)), build_binary_op (GE_EXPR, gnu_expr_type,
gnu_expr, gnu_min_expr); convert (gnu_expr_type,
} gnu_max_expr),
else convert (gnu_expr_type,
gnu_expr = TYPE_MIN_VALUE (TYPE_DOMAIN (gnu_result_type)); gnu_min_expr)),
gnu_expr,
TREE_CODE (gnu_min_expr) != INTEGER_CST
&& TREE_CODE (gnu_max_expr) == INTEGER_CST
? gnu_max_expr : gnu_min_expr);
}
else
/* Simply return the naked low bound. */
gnu_expr = TYPE_MIN_VALUE (TYPE_DOMAIN (gnu_result_type));
gnu_result = build_binary_op (ARRAY_RANGE_REF, gnu_result_type, gnu_result = build_binary_op (ARRAY_RANGE_REF, gnu_result_type,
gnu_result, gnu_expr); gnu_result, gnu_expr);
} }
break; break;
...@@ -3487,7 +3546,9 @@ gnat_to_gnu (Node_Id gnat_node) ...@@ -3487,7 +3546,9 @@ gnat_to_gnu (Node_Id gnat_node)
/* This case can apply to a boolean or a modular type. /* This case can apply to a boolean or a modular type.
Fall through for a boolean operand since GNU_CODES is set Fall through for a boolean operand since GNU_CODES is set
up to handle this. */ up to handle this. */
if (IN (Ekind (Etype (gnat_node)), Modular_Integer_Kind)) if (Is_Modular_Integer_Type (Etype (gnat_node))
|| (Ekind (Etype (gnat_node)) == E_Private_Type
&& Is_Modular_Integer_Type (Full_View (Etype (gnat_node)))))
{ {
gnu_expr = gnat_to_gnu (Right_Opnd (gnat_node)); gnu_expr = gnat_to_gnu (Right_Opnd (gnat_node));
gnu_result_type = get_unpadded_type (Etype (gnat_node)); gnu_result_type = get_unpadded_type (Etype (gnat_node));
...@@ -4473,7 +4534,7 @@ insert_code_for (Node_Id gnat_node) ...@@ -4473,7 +4534,7 @@ insert_code_for (Node_Id gnat_node)
/* Start a new statement group chained to the previous group. */ /* Start a new statement group chained to the previous group. */
static void static void
start_stmt_group () start_stmt_group (void)
{ {
struct stmt_group *group = stmt_group_free_list; struct stmt_group *group = stmt_group_free_list;
...@@ -4633,7 +4694,7 @@ set_block_for_group (tree gnu_block) ...@@ -4633,7 +4694,7 @@ set_block_for_group (tree gnu_block)
BLOCK or cleanups were set. */ BLOCK or cleanups were set. */
static tree static tree
end_stmt_group () end_stmt_group (void)
{ {
struct stmt_group *group = current_stmt_group; struct stmt_group *group = current_stmt_group;
tree gnu_retval = group->stmt_list; tree gnu_retval = group->stmt_list;
...@@ -5633,12 +5694,12 @@ addressable_p (tree gnu_expr) ...@@ -5633,12 +5694,12 @@ addressable_p (tree gnu_expr)
case COMPONENT_REF: case COMPONENT_REF:
return (!DECL_BIT_FIELD (TREE_OPERAND (gnu_expr, 1)) return (!DECL_BIT_FIELD (TREE_OPERAND (gnu_expr, 1))
&& (!STRICT_ALIGNMENT && (!STRICT_ALIGNMENT
/* If the field was marked as "semantically" addressable /* Even with DECL_BIT_FIELD cleared, we have to ensure that
in create_field_decl, we are guaranteed that it can the field is sufficiently aligned, in case it is subject
be directly addressed. */ to a pragma Component_Alignment. But we don't need to
|| !DECL_NONADDRESSABLE_P (TREE_OPERAND (gnu_expr, 1)) check the alignment of the containing record, as it is
/* Otherwise it can nevertheless be directly addressed guaranteed to be not smaller than that of its most
if it has been sufficiently aligned in the record. */ aligned field that is not a bit-field. */
|| DECL_ALIGN (TREE_OPERAND (gnu_expr, 1)) || DECL_ALIGN (TREE_OPERAND (gnu_expr, 1))
>= TYPE_ALIGN (TREE_TYPE (gnu_expr))) >= TYPE_ALIGN (TREE_TYPE (gnu_expr)))
&& addressable_p (TREE_OPERAND (gnu_expr, 0))); && addressable_p (TREE_OPERAND (gnu_expr, 0)));
...@@ -6004,8 +6065,8 @@ maybe_stabilize_reference (tree ref, bool force, bool lvalues_only, ...@@ -6004,8 +6065,8 @@ maybe_stabilize_reference (tree ref, bool force, bool lvalues_only,
case ADDR_EXPR: case ADDR_EXPR:
/* A standalone ADDR_EXPR is never an lvalue, and this one can't /* A standalone ADDR_EXPR is never an lvalue, and this one can't
be nested inside an outer INDIRECT_REF, since INDIREC_REF goes be nested inside an outer INDIRECT_REF, since INDIRECT_REF goes
straight to stabilize_1. */ straight to gnat_stabilize_reference_1. */
if (lvalues_only) if (lvalues_only)
goto failure; goto failure;
...@@ -6057,11 +6118,17 @@ maybe_stabilize_reference (tree ref, bool force, bool lvalues_only, ...@@ -6057,11 +6118,17 @@ maybe_stabilize_reference (tree ref, bool force, bool lvalues_only,
break; break;
case COMPOUND_EXPR: case COMPOUND_EXPR:
result = build2 (COMPOUND_EXPR, type, result = gnat_stabilize_reference_1 (ref, force);
gnat_stabilize_reference_1 (TREE_OPERAND (ref, 0), break;
force),
maybe_stabilize_reference (TREE_OPERAND (ref, 1), force, case CALL_EXPR:
lvalues_only, success)); if (lvalues_only)
goto failure;
/* This generates better code than the scheme in protect_multiple_eval
because large objects will be returned via invisible reference in
most ABIs so the temporary will directly be filled by the callee. */
result = gnat_stabilize_reference_1 (ref, force);
break; break;
case ERROR_MARK: case ERROR_MARK:
......
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