+2008-04-08 Eric Botcazou <ebotcazou@adacore.com>
+
+ * decl.c (gnat_to_gnu_entity) <object>: If -gnatd.a and not optimizing
+ alignment for space, promote the alignment of non-scalar variables with
+ no size and alignment.
+ * gigi.h (gnat_types_compatible_p): Declare.
+ * misc.c (LANG_HOOKS_TYPES_COMPATIBLE_P): Set to above predicate.
+ * trans.c (gnat_to_gnu): Revert revision 129339 change. Minor cleanup.
+ * utils.c (gnat_types_compatible_p) : New predicate.
+ (convert): Use it throughout to test for cases where a mere view
+ conversion is sufficient.
+ * utils2.c (build_binary_op): Minor tweaks.
+ (build_unary_op): Likewise.
+
2008-04-08 Eric Botcazou <ebotcazou@adacore.com>
* decl.c (adjust_packed): Expand comment.
&& !Present (Address_Clause (gnat_entity)))
gnu_size = bitsize_unit_node;
- /* If this is an atomic object with no specified size and alignment,
- but where the size of the type is a constant, set the alignment to
- the smallest not less than the size, or to the biggest meaningful
- alignment, whichever is smaller. */
- if (Is_Atomic (gnat_entity) && !gnu_size && align == 0
+ /* If this is an object with no specified size and alignment, and if
+ either it is atomic or we are not optimizing alignment for space
+ and it is a non-scalar variable, and the size of its type is a
+ constant, set the alignment to the smallest not less than the
+ size, or to the biggest meaningful one, whichever is smaller. */
+ if (!gnu_size && align == 0
+ && (Is_Atomic (gnat_entity)
+ || (Debug_Flag_Dot_A
+ && !Optimize_Alignment_Space (gnat_entity)
+ && kind == E_Variable
+ && AGGREGATE_TYPE_P (gnu_type)
+ && !const_flag && No (Renamed_Object (gnat_entity))
+ && !imported_p && No (Address_Clause (gnat_entity))))
&& TREE_CODE (TYPE_SIZE (gnu_type)) == INTEGER_CST)
{
+ /* No point in jumping through all the hoops needed in order
+ to support BIGGEST_ALIGNMENT if we don't really have to. */
+ unsigned int align_cap = Is_Atomic (gnat_entity)
+ ? BIGGEST_ALIGNMENT
+ : MAX_FIXED_MODE_SIZE;
+
if (!host_integerp (TYPE_SIZE (gnu_type), 1)
- || 0 <= compare_tree_int (TYPE_SIZE (gnu_type),
- BIGGEST_ALIGNMENT))
- align = BIGGEST_ALIGNMENT;
+ || compare_tree_int (TYPE_SIZE (gnu_type), align_cap) >= 0)
+ align = align_cap;
else
align = ceil_alignment (tree_low_cst (TYPE_SIZE (gnu_type), 1));
+
+ /* But make sure not to under-align the object. */
+ if (align < TYPE_ALIGN (gnu_type))
+ align = TYPE_ALIGN (gnu_type);
+
+ /* And honor the minimum valid atomic alignment, if any. */
+#ifdef MINIMUM_ATOMIC_ALIGNMENT
+ if (align < MINIMUM_ATOMIC_ALIGNMENT)
+ align = MINIMUM_ATOMIC_ALIGNMENT;
+#endif
}
/* If the object is set to have atomic components, find the component
/* Return the signed version of a TYPE_NODE, a scalar type. */
extern tree gnat_signed_type (tree type_node);
+/* Return 1 if the types T1 and T2 are compatible, i.e. if they can be
+ transparently converted to each other. */
+extern int gnat_types_compatible_p (tree t1, tree t2);
+
/* Create an expression whose value is that of EXPR,
converted to type TYPE. The TREE_TYPE of the value
is always TYPE. This function implements all reasonable
#define LANG_HOOKS_TYPE_FOR_MODE gnat_type_for_mode
#undef LANG_HOOKS_TYPE_FOR_SIZE
#define LANG_HOOKS_TYPE_FOR_SIZE gnat_type_for_size
+#undef LANG_HOOKS_TYPES_COMPATIBLE_P
+#define LANG_HOOKS_TYPES_COMPATIBLE_P gnat_types_compatible_p
#undef LANG_HOOKS_ATTRIBUTE_TABLE
#define LANG_HOOKS_ATTRIBUTE_TABLE gnat_internal_attribute_table
#undef LANG_HOOKS_BUILTIN_FUNCTION
|| CONTAINS_PLACEHOLDER_P (TYPE_SIZE (gnu_result_type))))
gnu_result = gnat_stabilize_reference (gnu_result, false);
- /* Now convert the result to the proper type. If the type is void or if
- we have no result, return error_mark_node to show we have no result.
- If the type of the result is correct or if we have a label (which doesn't
- have any well-defined type), return our result. Also don't do the
- conversion if the "desired" type involves a PLACEHOLDER_EXPR in its size
- since those are the cases where the front end may have the type wrong due
- to "instantiating" the unconstrained record with discriminant values
- or if this is a FIELD_DECL. If this is the Name of an assignment
- statement or a parameter of a procedure call, return what we have since
- the RHS has to be converted to our type there in that case, unless
- GNU_RESULT_TYPE has a simpler size. Similarly, if the two types are
- record types with the same name and GNU_RESULT_TYPE has BLKmode, don't
- convert. This will be the case when we are converting from a packable
- type to its actual type and we need those conversions to be NOPs in
- order for assignments into these types to work properly. Finally,
- don't convert integral types that are the operand of an unchecked
- conversion since we need to ignore those conversions (for 'Valid).
- Otherwise, convert the result to the proper type. */
+ /* Now convert the result to the result type, unless we are in one of the
+ following cases:
+
+ 1. If this is the Name of an assignment statement or a parameter of
+ a procedure call, return the result almost unmodified since the
+ RHS will have to be converted to our type in that case, unless
+ the result type has a simpler size. Similarly, don't convert
+ integral types that are the operands of an unchecked conversion
+ since we need to ignore those conversions (for 'Valid).
+
+ 2. If we have a label (which doesn't have any well-defined type), a
+ field or an error, return the result almost unmodified. Also don't
+ do the conversion if the result type involves a PLACEHOLDER_EXPR in
+ its size since those are the cases where the front end may have the
+ type wrong due to "instantiating" the unconstrained record with
+ discriminant values. Similarly, if the two types are record types
+ with the same name and the result type has BLKmode, don't convert.
+ This will be the case when we are converting from a packed version
+ of a type to its original type and we need those conversions to be
+ NOPs in order for assignments into these types to work properly.
+
+ 3. If the type is void or if we have no result, return error_mark_node
+ to show we have no result.
+
+ 4. Finally, if the type of the result is already correct. */
if (Present (Parent (gnat_node))
&& ((Nkind (Parent (gnat_node)) == N_Assignment_Statement
&& Name (Parent (gnat_node)) == gnat_node)
|| (Nkind (Parent (gnat_node)) == N_Procedure_Call_Statement
&& Name (Parent (gnat_node)) != gnat_node)
+ || Nkind (Parent (gnat_node)) == N_Parameter_Association
|| (Nkind (Parent (gnat_node)) == N_Unchecked_Type_Conversion
&& !AGGREGATE_TYPE_P (gnu_result_type)
- && !AGGREGATE_TYPE_P (TREE_TYPE (gnu_result)))
- || Nkind (Parent (gnat_node)) == N_Parameter_Association)
+ && !AGGREGATE_TYPE_P (TREE_TYPE (gnu_result))))
&& !(TYPE_SIZE (gnu_result_type)
&& TYPE_SIZE (TREE_TYPE (gnu_result))
&& (AGGREGATE_TYPE_P (gnu_result_type)
&& !(TREE_CODE (gnu_result_type) == RECORD_TYPE
&& TYPE_JUSTIFIED_MODULAR_P (gnu_result_type))))
{
- /* In this case remove padding only if the inner object type is the
- same as gnu_result_type or is of self-referential size (in that later
- case it must be an object of unconstrained type with a default
- discriminant). We want to avoid copying too much data. */
+ /* Remove padding only if the inner object is of self-referential
+ size: in that case it must be an object of unconstrained type
+ with a default discriminant and we want to avoid copying too
+ much data. */
if (TREE_CODE (TREE_TYPE (gnu_result)) == RECORD_TYPE
&& TYPE_IS_PADDING_P (TREE_TYPE (gnu_result))
- && (TREE_TYPE (TYPE_FIELDS (TREE_TYPE (gnu_result)))
- == gnu_result_type
- || CONTAINS_PLACEHOLDER_P (TYPE_SIZE (TREE_TYPE (TYPE_FIELDS
- (TREE_TYPE (gnu_result)))))))
+ && CONTAINS_PLACEHOLDER_P (TYPE_SIZE (TREE_TYPE (TYPE_FIELDS
+ (TREE_TYPE (gnu_result))))))
gnu_result = convert (TREE_TYPE (TYPE_FIELDS (TREE_TYPE (gnu_result))),
gnu_result);
}
&& TREE_CODE (TREE_TYPE (gnu_result)) == RECORD_TYPE
&& TYPE_MODE (gnu_result_type) == BLKmode))
{
- /* Remove any padding record, but do nothing more in this case. */
+ /* Remove any padding. */
if (TREE_CODE (TREE_TYPE (gnu_result)) == RECORD_TYPE
&& TYPE_IS_PADDING_P (TREE_TYPE (gnu_result)))
gnu_result = convert (TREE_TYPE (TYPE_FIELDS (TREE_TYPE (gnu_result))),
gnu_result);
}
- else if (gnu_result == error_mark_node
- || gnu_result_type == void_type_node)
- gnu_result = error_mark_node;
+ else if (gnu_result == error_mark_node || gnu_result_type == void_type_node)
+ gnu_result = error_mark_node;
+
else if (gnu_result_type != TREE_TYPE (gnu_result))
gnu_result = convert (gnu_result_type, gnu_result);
- /* We don't need any NOP_EXPR or NON_LVALUE_EXPR on GNU_RESULT. */
+ /* We don't need any NOP_EXPR or NON_LVALUE_EXPR on the result. */
while ((TREE_CODE (gnu_result) == NOP_EXPR
|| TREE_CODE (gnu_result) == NON_LVALUE_EXPR)
&& TREE_TYPE (TREE_OPERAND (gnu_result, 0)) == TREE_TYPE (gnu_result))
return type;
}
+/* Return 1 if the types T1 and T2 are compatible, i.e. if they can be
+ transparently converted to each other. */
+
+int
+gnat_types_compatible_p (tree t1, tree t2)
+{
+ enum tree_code code;
+
+ /* This is the default criterion. */
+ if (TYPE_MAIN_VARIANT (t1) == TYPE_MAIN_VARIANT (t2))
+ return 1;
+
+ /* We only check structural equivalence here. */
+ if ((code = TREE_CODE (t1)) != TREE_CODE (t2))
+ return 0;
+
+ /* Array types are also compatible if they are constrained and have
+ the same component type and the same domain. */
+ if (code == ARRAY_TYPE
+ && TREE_TYPE (t1) == TREE_TYPE (t2)
+ && tree_int_cst_equal (TYPE_MIN_VALUE (TYPE_DOMAIN (t1)),
+ TYPE_MIN_VALUE (TYPE_DOMAIN (t2)))
+ && tree_int_cst_equal (TYPE_MAX_VALUE (TYPE_DOMAIN (t1)),
+ TYPE_MAX_VALUE (TYPE_DOMAIN (t2))))
+ return 1;
+
+ /* Padding record types are also compatible if they pad the same
+ type and have the same constant size. */
+ if (code == RECORD_TYPE
+ && TYPE_IS_PADDING_P (t1) && TYPE_IS_PADDING_P (t2)
+ && TREE_TYPE (TYPE_FIELDS (t1)) == TREE_TYPE (TYPE_FIELDS (t2))
+ && tree_int_cst_equal (TYPE_SIZE (t1), TYPE_SIZE (t2)))
+ return 1;
+
+ return 0;
+}
\f
/* EXP is an expression for the size of an object. If this size contains
discriminant references, replace them with the maximum (if MAX_P) or
/* If both input and output have padding and are of variable size, do this
as an unchecked conversion. Likewise if one is a mere variant of the
other, so we avoid a pointless unpad/repad sequence. */
- else if (ecode == RECORD_TYPE && code == RECORD_TYPE
+ else if (code == RECORD_TYPE && ecode == RECORD_TYPE
&& TYPE_IS_PADDING_P (type) && TYPE_IS_PADDING_P (etype)
&& (!TREE_CONSTANT (TYPE_SIZE (type))
|| !TREE_CONSTANT (TYPE_SIZE (etype))
- || TYPE_MAIN_VARIANT (type) == TYPE_MAIN_VARIANT (etype)))
+ || gnat_types_compatible_p (type, etype)))
;
- /* If the output type has padding, make a constructor to build the
- record. */
+ /* If the output type has padding, convert to the inner type and
+ make a constructor to build the record. */
else if (code == RECORD_TYPE && TYPE_IS_PADDING_P (type))
{
/* If we previously converted from another type and our type is
expr = TREE_OPERAND (expr, 0);
/* If we are just removing the padding from expr, convert the original
- object if we have variable size. That will avoid the need
- for some variable-size temporaries. */
+ object if we have variable size in order to avoid the need for some
+ variable-size temporaries. Likewise if the padding is a mere variant
+ of the other, so we avoid a pointless unpad/repad sequence. */
if (TREE_CODE (expr) == COMPONENT_REF
&& TREE_CODE (TREE_TYPE (TREE_OPERAND (expr, 0))) == RECORD_TYPE
&& TYPE_IS_PADDING_P (TREE_TYPE (TREE_OPERAND (expr, 0)))
- && !TREE_CONSTANT (TYPE_SIZE (type)))
+ && (!TREE_CONSTANT (TYPE_SIZE (type))
+ || gnat_types_compatible_p (type,
+ TREE_TYPE (TREE_OPERAND (expr, 0)))))
return convert (type, TREE_OPERAND (expr, 0));
/* If the result type is a padded type with a self-referentially-sized
break;
case CONSTRUCTOR:
- /* If we are converting a CONSTRUCTOR to another constrained array type
- with the same domain, just make a new one in the proper type. */
- if (code == ecode && code == ARRAY_TYPE
- && TREE_TYPE (type) == TREE_TYPE (etype)
- && tree_int_cst_equal (TYPE_MIN_VALUE (TYPE_DOMAIN (type)),
- TYPE_MIN_VALUE (TYPE_DOMAIN (etype)))
- && tree_int_cst_equal (TYPE_MAX_VALUE (TYPE_DOMAIN (type)),
- TYPE_MAX_VALUE (TYPE_DOMAIN (etype))))
+ /* 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))
{
expr = copy_node (expr);
TREE_TYPE (expr) = type;
the inner operand to the output type is fine in most cases, it
might expose unexpected input/output type mismatches in special
circumstances so we avoid such recursive calls when we can. */
-
tree op0 = TREE_OPERAND (expr, 0);
/* If we are converting back to the original type, we can just
return op0;
/* Otherwise, if we're converting between two aggregate types, we
- might be allowed to substitute the VIEW_CONVERT target type in
- place or to just convert the inner expression. */
+ might be allowed to substitute the VIEW_CONVERT_EXPR target type
+ in place or to just convert the inner expression. */
if (AGGREGATE_TYPE_P (type) && AGGREGATE_TYPE_P (etype))
{
- /* If we are converting between type variants, we can just
- substitute the VIEW_CONVERT in place. */
- if (TYPE_MAIN_VARIANT (type) == TYPE_MAIN_VARIANT (etype))
+ /* If we are converting between mere variants, we can just
+ substitute the VIEW_CONVERT_EXPR in place. */
+ if (gnat_types_compatible_p (type, etype))
return build1 (VIEW_CONVERT_EXPR, type, op0);
/* Otherwise, we may just bypass the input view conversion unless
if (TYPE_FAT_POINTER_P (type) && !TYPE_FAT_POINTER_P (etype))
return convert_to_fat_pointer (type, expr);
- /* If we're converting between two aggregate types that have the same main
- variant, just make a VIEW_CONVER_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)
- && TYPE_MAIN_VARIANT (type) == TYPE_MAIN_VARIANT (etype))
+ && gnat_types_compatible_p (type, etype))
return build1 (VIEW_CONVERT_EXPR, type, expr);
/* In all other cases of related types, make a NOP_EXPR. */
tree right_base_type = get_base_type (right_type);
tree operation_type = result_type;
tree best_type = NULL_TREE;
- tree modulus;
- tree result;
+ tree modulus, result;
bool has_side_effects = false;
if (operation_type
&& TYPE_EXTRA_SUBTYPE_P (operation_type))
operation_type = get_base_type (operation_type);
- modulus = (operation_type && TREE_CODE (operation_type) == INTEGER_TYPE
+ modulus = (operation_type
+ && TREE_CODE (operation_type) == INTEGER_TYPE
&& TYPE_MODULAR_P (operation_type)
- ? TYPE_MODULUS (operation_type) : 0);
+ ? TYPE_MODULUS (operation_type) : NULL_TREE);
switch (op_code)
{
case MODIFY_EXPR:
- /* If there were any integral or pointer conversions on LHS, remove
+ /* If there were integral or pointer conversions on the LHS, remove
them; we'll be putting them back below if needed. Likewise for
- conversions between array and record types. But don't do this if
- the right operand is not BLKmode (for packed arrays)
- unless we are not changing the mode. */
+ conversions between array and record types, except for justified
+ modular types. But don't do this if the right operand is not
+ BLKmode (for packed arrays) unless we are not changing the mode. */
while ((TREE_CODE (left_operand) == CONVERT_EXPR
|| TREE_CODE (left_operand) == NOP_EXPR
|| TREE_CODE (left_operand) == VIEW_CONVERT_EXPR)
|| POINTER_TYPE_P (TREE_TYPE
(TREE_OPERAND (left_operand, 0)))))
|| (((TREE_CODE (left_type) == RECORD_TYPE
- /* Don't remove conversions to justified modular
- types. */
&& !TYPE_JUSTIFIED_MODULAR_P (left_type))
|| TREE_CODE (left_type) == ARRAY_TYPE)
&& ((TREE_CODE (TREE_TYPE
if (!operation_type)
operation_type = left_type;
- /* If we are copying one array or record to another, find the best type
- to use. */
+ /* Find the best type to use for copying between aggregate types. */
if (((TREE_CODE (left_type) == ARRAY_TYPE
&& TREE_CODE (right_type) == ARRAY_TYPE)
|| (TREE_CODE (left_type) == RECORD_TYPE
/* Ensure everything on the LHS is valid. If we have a field reference,
strip anything that get_inner_reference can handle. Then remove any
- conversions with type types having the same code and mode. Mark
+ conversions between types having the same code and mode. And mark
VIEW_CONVERT_EXPRs with TREE_ADDRESSABLE. When done, we must have
- either an INDIRECT_REF or a decl. */
+ either an INDIRECT_REF, a NULL_EXPR or a DECL node. */
result = left_operand;
- while (1)
+ while (true)
{
tree restype = TREE_TYPE (result);
}
gcc_assert (TREE_CODE (result) == INDIRECT_REF
- || TREE_CODE (result) == NULL_EXPR || DECL_P (result));
+ || TREE_CODE (result) == NULL_EXPR
+ || DECL_P (result));
- /* Convert the right operand to the operation type unless
- it is either already of the correct type or if the type
- involves a placeholder, since the RHS may not have the same
- record type. */
+ /* Convert the right operand to the operation type unless it is
+ either already of the correct type or if the type involves a
+ placeholder, since the RHS may not have the same record type. */
if (operation_type != right_type
- && (!CONTAINS_PLACEHOLDER_P (TYPE_SIZE (operation_type))))
+ && !CONTAINS_PLACEHOLDER_P (TYPE_SIZE (operation_type)))
{
right_operand = convert (operation_type, right_operand);
right_type = operation_type;
}
- /* If the left operand is not the same type as the operation type,
- surround it in a VIEW_CONVERT_EXPR. */
+ /* If the left operand is not of the same type as the operation
+ type, wrap it up in a VIEW_CONVERT_EXPR. */
if (left_type != operation_type)
left_operand = unchecked_convert (operation_type, left_operand, false);
tree modulus = ((operation_type
&& TREE_CODE (operation_type) == INTEGER_TYPE
&& TYPE_MODULAR_P (operation_type))
- ? TYPE_MODULUS (operation_type) : 0);
+ ? TYPE_MODULUS (operation_type) : NULL_TREE);
int mod_pow2 = modulus && integer_pow2p (modulus);
/* If this is a modular type, there are various possibilities