decl.c (maybe_pad_type): Try to get a form of the type with integral mode even if...

* decl.c (maybe_pad_type): Try to get a form of the type with integral
	mode even if the alignment is not a factor of the original size.  But
	make sure to create the inner field with the original size.  Reorder.
	* trans.c (addressable_p) <COMPONENT_REF>: Treat the field of a padding
	record as always addressable.
	* utils.c (convert): Deal specially with conversions between original
	and packable versions of a record type.
	* utils2.c (build_binary_op) <MODIFY_EXPR>: Be more restrictive when
	recognizing an assignment between padded objects.

From-SVN: r134916
This commit is contained in:
Eric Botcazou 2008-05-03 19:35:01 +00:00 committed by Eric Botcazou
parent 093daf0fc7
commit 88f36b7eb6
9 changed files with 131 additions and 84 deletions

View File

@ -1,3 +1,15 @@
2008-05-03 Eric Botcazou <ebotcazou@adacore.com>
* decl.c (maybe_pad_type): Try to get a form of the type with integral
mode even if the alignment is not a factor of the original size. But
make sure to create the inner field with the original size. Reorder.
* trans.c (addressable_p) <COMPONENT_REF>: Treat the field of a padding
record as always addressable.
* utils.c (convert): Deal specially with conversions between original
and packable versions of a record type.
* utils2.c (build_binary_op) <MODIFY_EXPR>: Be more restrictive when
recognizing an assignment between padded objects.
2008-05-01 Eric Botcazou <ebotcazou@adacore.com>
* decl.c (make_packable_type): Resize the last component to its RM size

View File

@ -5448,9 +5448,9 @@ make_packable_type (tree type, bool in_record)
new_type = make_node (TREE_CODE (type));
/* Copy the name and flags from the old type to that of the new. Note
that we rely on the pointer equality created here for TYPE_NAME at
the end of gnat_to_gnu. */
/* Copy the name and flags from the old type to that of the new.
Note that we rely on the pointer equality created here for
TYPE_NAME to look through conversions in various places. */
TYPE_NAME (new_type) = TYPE_NAME (type);
TYPE_JUSTIFIED_MODULAR_P (new_type) = TYPE_JUSTIFIED_MODULAR_P (type);
TYPE_CONTAINS_TEMPLATE_P (new_type) = TYPE_CONTAINS_TEMPLATE_P (type);
@ -5576,7 +5576,7 @@ make_packable_type (tree type, bool in_record)
GNAT_ENTITY and NAME_TRAILER are used to name the resulting record and
to issue a warning.
IS_USER_TYPE is true if we must be sure we complete the original type.
IS_USER_TYPE is true if we must complete the original type.
DEFINITION is true if this type is being defined.
@ -5634,16 +5634,7 @@ maybe_pad_type (tree type, tree size, unsigned int align,
if (align == 0 && !size)
return type;
/* We used to modify the record in place in some cases, but that could
generate incorrect debugging information. So make a new record
type and name. */
record = make_node (RECORD_TYPE);
if (Present (gnat_entity))
TYPE_NAME (record) = create_concat_name (gnat_entity, name_trailer);
/* If we were making a type, complete the original type and give it a
name. */
/* If requested, complete the original type and give it a name. */
if (is_user_type)
create_type_decl (get_entity_name (gnat_entity), type,
NULL, !Comes_From_Source (gnat_entity),
@ -5652,41 +5643,56 @@ maybe_pad_type (tree type, tree size, unsigned int align,
&& DECL_IGNORED_P (TYPE_NAME (type))),
gnat_entity);
/* If we are changing the alignment and the input type is a record with
BLKmode and a small constant size, try to make a form that has an
integral mode. That might allow this record to have an integral mode,
which will be much more efficient. There is no point in doing this if a
size is specified unless it is also smaller than the maximum mode size
and it is incorrect to do this if the size of the original type is not a
multiple of the alignment. */
if (align != 0
&& TREE_CODE (type) == RECORD_TYPE
&& TYPE_MODE (type) == BLKmode
&& TREE_CODE (orig_size) == INTEGER_CST
&& compare_tree_int (orig_size, MAX_FIXED_MODE_SIZE) <= 0
&& (!size
|| (TREE_CODE (size) == INTEGER_CST
&& compare_tree_int (size, MAX_FIXED_MODE_SIZE) <= 0))
&& value_factor_p (orig_size, align))
type = make_packable_type (type, true);
/* We used to modify the record in place in some cases, but that could
generate incorrect debugging information. So make a new record
type and name. */
record = make_node (RECORD_TYPE);
TYPE_IS_PADDING_P (record) = 1;
field = create_field_decl (get_identifier ("F"), type, record, 0,
NULL_TREE, bitsize_zero_node, 1);
if (Present (gnat_entity))
TYPE_NAME (record) = create_concat_name (gnat_entity, name_trailer);
DECL_INTERNAL_P (field) = 1;
TYPE_SIZE (record) = size ? size : orig_size;
TYPE_SIZE_UNIT (record)
= (size ? convert (sizetype,
size_binop (CEIL_DIV_EXPR, size, bitsize_unit_node))
: TYPE_SIZE_UNIT (type));
TYPE_VOLATILE (record)
= Present (gnat_entity) && Treat_As_Volatile (gnat_entity);
TYPE_ALIGN (record) = align;
if (orig_align)
TYPE_USER_ALIGN (record) = align;
TYPE_IS_PADDING_P (record) = 1;
TYPE_VOLATILE (record)
= Present (gnat_entity) && Treat_As_Volatile (gnat_entity);
TYPE_SIZE (record) = size ? size : orig_size;
TYPE_SIZE_UNIT (record)
= convert (sizetype,
size_binop (CEIL_DIV_EXPR, TYPE_SIZE (record),
bitsize_unit_node));
/* If we are changing the alignment and the input type is a record with
BLKmode and a small constant size, try to make a form that has an
integral mode. This might allow the padding record to also have an
integral mode, which will be much more efficient. There is no point
in doing so if a size is specified unless it is also a small constant
size and it is incorrect to do so if we cannot guarantee that the mode
will be naturally aligned since the field must always be addressable. */
if (align != 0
&& TREE_CODE (type) == RECORD_TYPE
&& TYPE_MODE (type) == BLKmode
&& TREE_CODE (orig_size) == INTEGER_CST
&& !TREE_CONSTANT_OVERFLOW (orig_size)
&& compare_tree_int (orig_size, MAX_FIXED_MODE_SIZE) <= 0
&& (!size
|| (TREE_CODE (size) == INTEGER_CST
&& compare_tree_int (size, MAX_FIXED_MODE_SIZE) <= 0)))
{
tree packable_type = make_packable_type (type, true);
if (TYPE_MODE (packable_type) != BLKmode
&& align >= TYPE_ALIGN (packable_type))
type = packable_type;
}
/* Now create the field with the original size. */
field = create_field_decl (get_identifier ("F"), type, record, 0,
orig_size, bitsize_zero_node, 1);
DECL_INTERNAL_P (field) = 1;
/* Do not finalize it until after the auxiliary record is built. */
finish_record_type (record, field, 1, true);

View File

@ -202,7 +202,7 @@ static tree emit_range_check (tree, Node_Id);
static tree emit_index_check (tree, tree, tree, tree);
static tree emit_check (tree, tree, int);
static tree convert_with_check (Entity_Id, tree, bool, bool, bool);
static bool larger_record_type_p (tree, tree);
static bool smaller_packable_type_p (tree, tree);
static bool addressable_p (tree, tree);
static tree assoc_to_constructor (Entity_Id, Node_Id, tree);
static tree extract_values (tree, tree);
@ -2204,11 +2204,11 @@ call_to_gnu (Node_Id gnat_node, tree *gnu_result_type_p, tree gnu_target)
of the object if they are distinct, because the expectations
of the callee would otherwise not be met:
- if it's a justified modular type,
- if the actual type is a packable version of it. */
- if the actual type is a smaller packable version of it. */
else if (TREE_CODE (gnu_name_type) == RECORD_TYPE
&& (TYPE_JUSTIFIED_MODULAR_P (gnu_name_type)
|| larger_record_type_p (gnu_name_type,
TREE_TYPE (gnu_name))))
|| smaller_packable_type_p (TREE_TYPE (gnu_name),
gnu_name_type)))
gnu_name = convert (gnu_name_type, gnu_name);
/* Make a SAVE_EXPR to both properly account for potential side
@ -6120,21 +6120,25 @@ convert_with_check (Entity_Id gnat_type, tree gnu_expr, bool overflowp,
return convert (gnu_type, gnu_result);
}
/* Return true if RECORD_TYPE, a record type, is larger than TYPE. */
/* Return true if TYPE is a smaller packable version of RECORD_TYPE. */
static bool
larger_record_type_p (tree record_type, tree type)
smaller_packable_type_p (tree type, tree record_type)
{
tree rsize, size;
tree size, rsize;
/* Padding types are not considered larger on their own. */
if (TYPE_IS_PADDING_P (record_type))
/* We're not interested in variants here. */
if (TYPE_MAIN_VARIANT (type) == TYPE_MAIN_VARIANT (record_type))
return false;
rsize = TYPE_SIZE (record_type);
size = TYPE_SIZE (type);
/* Like a variant, a packable version keeps the original TYPE_NAME. */
if (TYPE_NAME (type) != TYPE_NAME (record_type))
return false;
if (!(TREE_CODE (rsize) == INTEGER_CST && TREE_CODE (size) == INTEGER_CST))
size = TYPE_SIZE (type);
rsize = TYPE_SIZE (record_type);
if (!(TREE_CODE (size) == INTEGER_CST && TREE_CODE (rsize) == INTEGER_CST))
return false;
return tree_int_cst_lt (size, rsize) != 0;
@ -6208,7 +6212,7 @@ addressable_p (tree gnu_expr, tree gnu_type)
to be considered in practice. */
if (gnu_type
&& TREE_CODE (gnu_type) == RECORD_TYPE
&& larger_record_type_p (gnu_type, TREE_TYPE (gnu_expr)))
&& smaller_packable_type_p (TREE_TYPE (gnu_expr), gnu_type))
return false;
switch (TREE_CODE (gnu_expr))
@ -6238,16 +6242,18 @@ addressable_p (tree gnu_expr, tree gnu_type)
&& addressable_p (TREE_OPERAND (gnu_expr, 2), NULL_TREE));
case COMPONENT_REF:
return (!DECL_BIT_FIELD (TREE_OPERAND (gnu_expr, 1))
&& (!STRICT_ALIGNMENT
return (((!DECL_BIT_FIELD (TREE_OPERAND (gnu_expr, 1))
/* Even with DECL_BIT_FIELD cleared, we have to ensure that
the field is sufficiently aligned, in case it is subject
to a pragma Component_Alignment. But we don't need to
check the alignment of the containing record, as it is
guaranteed to be not smaller than that of its most
aligned field that is not a bit-field. */
&& (!STRICT_ALIGNMENT
|| DECL_ALIGN (TREE_OPERAND (gnu_expr, 1))
>= TYPE_ALIGN (TREE_TYPE (gnu_expr)))
>= TYPE_ALIGN (TREE_TYPE (gnu_expr))))
/* The field of a padding record is always addressable. */
|| TYPE_IS_PADDING_P (TREE_TYPE (TREE_OPERAND (gnu_expr, 0))))
&& addressable_p (TREE_OPERAND (gnu_expr, 0), NULL_TREE));
case ARRAY_REF: case ARRAY_RANGE_REF:

View File

@ -3396,7 +3396,9 @@ convert (tree type, tree expr)
&& TYPE_IS_PADDING_P (type) && TYPE_IS_PADDING_P (etype)
&& (!TREE_CONSTANT (TYPE_SIZE (type))
|| !TREE_CONSTANT (TYPE_SIZE (etype))
|| gnat_types_compatible_p (type, etype)))
|| gnat_types_compatible_p (type, etype)
|| TYPE_NAME (TREE_TYPE (TYPE_FIELDS (type)))
== TYPE_NAME (TREE_TYPE (TYPE_FIELDS (etype)))))
;
/* If the output type has padding, convert to the inner type and
@ -3405,9 +3407,13 @@ convert (tree type, tree expr)
{
/* If we previously converted from another type and our type is
of variable size, remove the conversion to avoid the need for
variable-size temporaries. */
variable-size temporaries. Likewise for a conversion between
original and packable version. */
if (TREE_CODE (expr) == VIEW_CONVERT_EXPR
&& !TREE_CONSTANT (TYPE_SIZE (type)))
&& (!TREE_CONSTANT (TYPE_SIZE (type))
|| (ecode == RECORD_TYPE
&& TYPE_NAME (etype)
== TYPE_NAME (TREE_TYPE (TREE_OPERAND (expr, 0))))))
expr = TREE_OPERAND (expr, 0);
/* If we are just removing the padding from expr, convert the original
@ -3419,7 +3425,10 @@ convert (tree type, tree expr)
&& TYPE_IS_PADDING_P (TREE_TYPE (TREE_OPERAND (expr, 0)))
&& (!TREE_CONSTANT (TYPE_SIZE (type))
|| gnat_types_compatible_p (type,
TREE_TYPE (TREE_OPERAND (expr, 0)))))
TREE_TYPE (TREE_OPERAND (expr, 0)))
|| (ecode == RECORD_TYPE
&& TYPE_NAME (etype)
== TYPE_NAME (TREE_TYPE (TYPE_FIELDS (type))))))
return convert (type, TREE_OPERAND (expr, 0));
/* If the result type is a padded type with a self-referentially-sized
@ -3534,8 +3543,12 @@ convert (tree type, tree expr)
case CONSTRUCTOR:
/* If we are converting a CONSTRUCTOR to a mere variant type, just make
a new one in the proper type. */
if (gnat_types_compatible_p (type, etype))
a new one in the proper type. Likewise for a conversion between
original and packable version. */
if (code == ecode
&& (gnat_types_compatible_p (type, etype)
|| (code == RECORD_TYPE
&& TYPE_NAME (type) == TYPE_NAME (etype))))
{
expr = copy_node (expr);
TREE_TYPE (expr) = type;
@ -3617,7 +3630,8 @@ convert (tree type, tree expr)
/* If we're converting between two aggregate types that are mere
variants, just make a VIEW_CONVERT_EXPR. */
else if (AGGREGATE_TYPE_P (type)
else if (code == ecode
&& AGGREGATE_TYPE_P (type)
&& gnat_types_compatible_p (type, etype))
return build1 (VIEW_CONVERT_EXPR, type, expr);

View File

@ -693,21 +693,24 @@ build_binary_op (enum tree_code op_code, tree result_type,
&& TYPE_ALIGN_OK (right_type))
operation_type = right_type;
/* If we are copying between padded objects of the same underlying
type with a non-zero size, use the padded view of the type, this
is very likely more efficient; but gnat_to_gnu will have removed
the padding on the RHS so we have to make sure that we can safely
put it back. */
/* If we are copying between padded objects with compatible types, use
the padded view of the objects, this is very likely more efficient.
Likewise for a padded that is assigned a constructor, in order to
avoid putting a VIEW_CONVERT_EXPR on the LHS. But don't do this if
we wouldn't have actually copied anything. */
else if (TREE_CODE (left_type) == RECORD_TYPE
&& TYPE_IS_PADDING_P (left_type)
&& TREE_TYPE (TYPE_FIELDS (left_type)) == right_type
&& !integer_zerop (TYPE_SIZE (right_type))
&& TREE_CONSTANT (TYPE_SIZE (left_type))
&& ((TREE_CODE (right_operand) == COMPONENT_REF
&& TREE_CODE (TREE_TYPE (TREE_OPERAND (right_operand, 0)))
== RECORD_TYPE
&& TYPE_IS_PADDING_P
(TREE_TYPE (TREE_OPERAND (right_operand, 0))))
|| TREE_CODE (right_operand) == CONSTRUCTOR))
(TREE_TYPE (TREE_OPERAND (right_operand, 0)))
&& gnat_types_compatible_p
(left_type,
TREE_TYPE (TREE_OPERAND (right_operand, 0))))
|| TREE_CODE (right_operand) == CONSTRUCTOR)
&& !integer_zerop (TYPE_SIZE (right_type)))
operation_type = left_type;
/* Find the best type to use for copying between aggregate types. */

View File

@ -1,3 +1,9 @@
2008-05-03 Eric Botcazou <ebotcazou@adacore.com>
* gnat.dg/alignment4.adb: Adjust.
* gnat.dg/alignment5.adb: Likewise.
* gnat.dg/alignment6.adb: XFAIL.
2008-05-03 Richard Guenther <rguenther@suse.de>
* gcc.dg/tree-ssa/loop-36.c: Cleanup the dump file.

View File

@ -11,5 +11,5 @@ begin
S1 := S2;
end;
-- { dg-final { scan-tree-dump-not "VIEW_CONVERT_EXPR" "gimple" } }
-- { dg-final { scan-tree-dump-not ".\F" "gimple" } }
-- { dg-final { cleanup-tree-dump "gimple" } }

View File

@ -27,5 +27,5 @@ begin
A_REC := B_REC;
end;
-- { dg-final { scan-tree-dump-not "VIEW_CONVERT_EXPR" "gimple" } }
-- { dg-final { scan-tree-dump-not "\.F" "gimple" } }
-- { dg-final { cleanup-tree-dump "gimple" } }

View File

@ -28,5 +28,5 @@ begin
B_REC := A_REC;
end;
-- { dg-final { scan-tree-dump-not "VIEW_CONVERT_EXPR" "gimple" } }
-- { dg-final { scan-tree-dump-not "VIEW_CONVERT_EXPR" "gimple" { xfail *-*-* } } }
-- { dg-final { cleanup-tree-dump "gimple" } }