From: Eric Botcazou Date: Tue, 8 Apr 2008 11:41:59 +0000 (+0000) Subject: decl.c (gnat_to_gnu_entity): If -gnatd.a and not optimizing alignment for space... X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=ba3f46d0910139e56300a68bc7992c0217b7adb9;p=gcc.git decl.c (gnat_to_gnu_entity): If -gnatd.a and not optimizing alignment for space... * decl.c (gnat_to_gnu_entity) : 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. From-SVN: r134092 --- diff --git a/gcc/ada/ChangeLog b/gcc/ada/ChangeLog index 7dc5d0fd39d..8a6c4b5069f 100644 --- a/gcc/ada/ChangeLog +++ b/gcc/ada/ChangeLog @@ -1,3 +1,17 @@ +2008-04-08 Eric Botcazou + + * decl.c (gnat_to_gnu_entity) : 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 * decl.c (adjust_packed): Expand comment. diff --git a/gcc/ada/decl.c b/gcc/ada/decl.c index 2d4742dd06b..bc5d4283053 100644 --- a/gcc/ada/decl.c +++ b/gcc/ada/decl.c @@ -672,19 +672,42 @@ gnat_to_gnu_entity (Entity_Id gnat_entity, tree gnu_expr, int definition) && !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 diff --git a/gcc/ada/gigi.h b/gcc/ada/gigi.h index 21ea4fe41fd..b35604447e1 100644 --- a/gcc/ada/gigi.h +++ b/gcc/ada/gigi.h @@ -468,6 +468,10 @@ extern tree gnat_unsigned_type (tree type_node); /* 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 diff --git a/gcc/ada/misc.c b/gcc/ada/misc.c index 317ec2d6cdc..a4dd99c5c2d 100644 --- a/gcc/ada/misc.c +++ b/gcc/ada/misc.c @@ -151,6 +151,8 @@ static tree gnat_type_max_size (const_tree); #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 diff --git a/gcc/ada/trans.c b/gcc/ada/trans.c index f3dc87dd43d..82aaa99140c 100644 --- a/gcc/ada/trans.c +++ b/gcc/ada/trans.c @@ -4832,34 +4832,41 @@ gnat_to_gnu (Node_Id gnat_node) || 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) @@ -4874,16 +4881,14 @@ gnat_to_gnu (Node_Id gnat_node) && !(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); } @@ -4901,20 +4906,20 @@ gnat_to_gnu (Node_Id gnat_node) && 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)) diff --git a/gcc/ada/utils.c b/gcc/ada/utils.c index 5c962170c8e..5186ccb076e 100644 --- a/gcc/ada/utils.c +++ b/gcc/ada/utils.c @@ -2378,6 +2378,42 @@ gnat_signed_type (tree type_node) 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; +} /* 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 @@ -3368,15 +3404,15 @@ convert (tree type, tree expr) /* 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 @@ -3387,12 +3423,15 @@ convert (tree type, tree expr) 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 @@ -3506,14 +3545,9 @@ convert (tree type, tree expr) 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; @@ -3539,7 +3573,6 @@ convert (tree type, tree expr) 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 @@ -3549,13 +3582,13 @@ convert (tree type, tree expr) 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 @@ -3594,10 +3627,10 @@ convert (tree type, tree expr) 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. */ diff --git a/gcc/ada/utils2.c b/gcc/ada/utils2.c index 8eddde2fb37..e680d090ba0 100644 --- a/gcc/ada/utils2.c +++ b/gcc/ada/utils2.c @@ -633,8 +633,7 @@ build_binary_op (enum tree_code op_code, tree result_type, 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 @@ -647,18 +646,19 @@ build_binary_op (enum tree_code op_code, tree result_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) @@ -669,8 +669,6 @@ build_binary_op (enum tree_code op_code, tree result_type, || 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 @@ -692,8 +690,7 @@ build_binary_op (enum tree_code op_code, tree result_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 @@ -709,11 +706,11 @@ build_binary_op (enum tree_code op_code, tree result_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); @@ -744,21 +741,21 @@ build_binary_op (enum tree_code op_code, tree result_type, } 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); @@ -1286,7 +1283,7 @@ build_unary_op (enum tree_code op_code, tree result_type, tree operand) 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