From: Eric Botcazou Date: Sat, 3 May 2008 19:35:01 +0000 (+0000) Subject: decl.c (maybe_pad_type): Try to get a form of the type with integral mode even if... X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=88f36b7eb6a153a914e9b4d678c1ddaddb842747;p=gcc.git 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) : 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) : Be more restrictive when recognizing an assignment between padded objects. From-SVN: r134916 --- diff --git a/gcc/ada/ChangeLog b/gcc/ada/ChangeLog index b1f1a6c0312..6da64b62973 100644 --- a/gcc/ada/ChangeLog +++ b/gcc/ada/ChangeLog @@ -1,3 +1,15 @@ +2008-05-03 Eric Botcazou + + * 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) : 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) : Be more restrictive when + recognizing an assignment between padded objects. + 2008-05-01 Eric Botcazou * decl.c (make_packable_type): Resize the last component to its RM size diff --git a/gcc/ada/decl.c b/gcc/ada/decl.c index 8dec1be1512..9d933b740d0 100644 --- a/gcc/ada/decl.c +++ b/gcc/ada/decl.c @@ -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,59 +5634,65 @@ maybe_pad_type (tree type, tree size, unsigned int align, 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); diff --git a/gcc/ada/trans.c b/gcc/ada/trans.c index 404b42f2282..5ec3ecdd013 100644 --- a/gcc/ada/trans.c +++ b/gcc/ada/trans.c @@ -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; + + /* 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; @@ -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 - /* 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: diff --git a/gcc/ada/utils.c b/gcc/ada/utils.c index d6a2234e747..8d3df68fe40 100644 --- a/gcc/ada/utils.c +++ b/gcc/ada/utils.c @@ -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); diff --git a/gcc/ada/utils2.c b/gcc/ada/utils2.c index f2eaf5e6d86..b45c7aca107 100644 --- a/gcc/ada/utils2.c +++ b/gcc/ada/utils2.c @@ -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. */ diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 1eea8481071..53a4fc0d2bd 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,9 @@ +2008-05-03 Eric Botcazou + + * gnat.dg/alignment4.adb: Adjust. + * gnat.dg/alignment5.adb: Likewise. + * gnat.dg/alignment6.adb: XFAIL. + 2008-05-03 Richard Guenther * gcc.dg/tree-ssa/loop-36.c: Cleanup the dump file. diff --git a/gcc/testsuite/gnat.dg/alignment4.adb b/gcc/testsuite/gnat.dg/alignment4.adb index ebc105367cb..c23bcfe48da 100644 --- a/gcc/testsuite/gnat.dg/alignment4.adb +++ b/gcc/testsuite/gnat.dg/alignment4.adb @@ -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" } } diff --git a/gcc/testsuite/gnat.dg/alignment5.adb b/gcc/testsuite/gnat.dg/alignment5.adb index 4cc2d18db94..8a89f5ef895 100644 --- a/gcc/testsuite/gnat.dg/alignment5.adb +++ b/gcc/testsuite/gnat.dg/alignment5.adb @@ -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" } } diff --git a/gcc/testsuite/gnat.dg/alignment6.adb b/gcc/testsuite/gnat.dg/alignment6.adb index f2889a50ecf..548574f5cc9 100644 --- a/gcc/testsuite/gnat.dg/alignment6.adb +++ b/gcc/testsuite/gnat.dg/alignment6.adb @@ -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" } }