+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
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);
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.
if (align == 0 && !size)
return type;
+ /* 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),
+ !(TYPE_NAME (type)
+ && TREE_CODE (TYPE_NAME (type)) == TYPE_DECL
+ && DECL_IGNORED_P (TYPE_NAME (type))),
+ gnat_entity);
+
/* 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;
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 (is_user_type)
- create_type_decl (get_entity_name (gnat_entity), type,
- NULL, !Comes_From_Source (gnat_entity),
- !(TYPE_NAME (type)
- && TREE_CODE (TYPE_NAME (type)) == TYPE_DECL
- && DECL_IGNORED_P (TYPE_NAME (type))),
- gnat_entity);
+ TYPE_VOLATILE (record)
+ = Present (gnat_entity) && Treat_As_Volatile (gnat_entity);
+
+ TYPE_ALIGN (record) = align;
+ if (orig_align)
+ TYPE_USER_ALIGN (record) = align;
+
+ 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. 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. */
+ 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))
- && value_factor_p (orig_size, align))
- type = make_packable_type (type, true);
+ && 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,
- NULL_TREE, bitsize_zero_node, 1);
-
+ orig_size, bitsize_zero_node, 1);
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_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);
/* Do not finalize it until after the auxiliary record is built. */
finish_record_type (record, field, 1, true);
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);
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
return convert (gnu_type, gnu_result);
}
\f
-/* 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;
+
+ /* Like a variant, a packable version keeps the original TYPE_NAME. */
+ if (TYPE_NAME (type) != TYPE_NAME (record_type))
return false;
- rsize = TYPE_SIZE (record_type);
size = TYPE_SIZE (type);
+ rsize = TYPE_SIZE (record_type);
- if (!(TREE_CODE (rsize) == INTEGER_CST && TREE_CODE (size) == INTEGER_CST))
+ if (!(TREE_CODE (size) == INTEGER_CST && TREE_CODE (rsize) == INTEGER_CST))
return false;
return tree_int_cst_lt (size, rsize) != 0;
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))
&& addressable_p (TREE_OPERAND (gnu_expr, 2), NULL_TREE));
case COMPONENT_REF:
- return (!DECL_BIT_FIELD (TREE_OPERAND (gnu_expr, 1))
- && (!STRICT_ALIGNMENT
- /* 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. */
- || DECL_ALIGN (TREE_OPERAND (gnu_expr, 1))
- >= TYPE_ALIGN (TREE_TYPE (gnu_expr)))
+ 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))))
+ /* 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:
&& 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
{
/* 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
&& 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
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;
/* 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);
&& 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. */
+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.
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" } }
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" } }
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" } }