From 8853cb0bcdbbf5424ceeed44778e302c4249532b Mon Sep 17 00:00:00 2001 From: Eric Botcazou Date: Sat, 8 Mar 2008 11:30:26 +0000 Subject: [PATCH] utils.c (finish_record_type): Clear DECL_BIT_FIELD on sufficiently aligned bit-fields... * utils.c (finish_record_type): Clear DECL_BIT_FIELD on sufficiently aligned bit-fields, bumping the alignment of the record type if deemed profitable. (value_factor_p): Return false instead of 0. From-SVN: r133028 --- gcc/ada/ChangeLog | 7 +++++ gcc/ada/utils.c | 54 +++++++++++++++++++++++++++------ gcc/testsuite/ChangeLog | 4 +++ gcc/testsuite/gnat.dg/pack4.adb | 38 +++++++++++++++++++++++ 4 files changed, 93 insertions(+), 10 deletions(-) create mode 100644 gcc/testsuite/gnat.dg/pack4.adb diff --git a/gcc/ada/ChangeLog b/gcc/ada/ChangeLog index 2a10f10f1b6..77ceedae6ff 100644 --- a/gcc/ada/ChangeLog +++ b/gcc/ada/ChangeLog @@ -1,3 +1,10 @@ +2008-03-08 Eric Botcazou + + * utils.c (finish_record_type): Clear DECL_BIT_FIELD on sufficiently + aligned bit-fields, bumping the alignment of the record type if deemed + profitable. + (value_factor_p): Return false instead of 0. + 2008-03-08 Eric Botcazou * decl.c (gnat_to_gnu_entity) : Add support diff --git a/gcc/ada/utils.c b/gcc/ada/utils.c index 46ce865bdb4..f1ffa4f7b29 100644 --- a/gcc/ada/utils.c +++ b/gcc/ada/utils.c @@ -752,6 +752,7 @@ finish_record_type (tree record_type, tree fieldlist, int rep_level, tree size = bitsize_zero_node; bool had_size = TYPE_SIZE (record_type) != 0; bool had_size_unit = TYPE_SIZE_UNIT (record_type) != 0; + bool had_align = TYPE_ALIGN (record_type) != 0; tree field; if (name && TREE_CODE (name) == TYPE_DECL) @@ -804,24 +805,55 @@ finish_record_type (tree record_type, tree fieldlist, int rep_level, for (field = fieldlist; field; field = TREE_CHAIN (field)) { - tree pos = bit_position (field); - tree type = TREE_TYPE (field); + tree pos = bit_position (field); tree this_size = DECL_SIZE (field); - tree this_ada_size = DECL_SIZE (field); + tree this_ada_size; - if ((TREE_CODE (type) == RECORD_TYPE || TREE_CODE (type) == UNION_TYPE - || TREE_CODE (type) == QUAL_UNION_TYPE) + if ((TREE_CODE (type) == RECORD_TYPE + || TREE_CODE (type) == UNION_TYPE + || TREE_CODE (type) == QUAL_UNION_TYPE) && !TYPE_IS_FAT_POINTER_P (type) && !TYPE_CONTAINS_TEMPLATE_P (type) && TYPE_ADA_SIZE (type)) this_ada_size = TYPE_ADA_SIZE (type); + else + this_ada_size = this_size; /* Clear DECL_BIT_FIELD for the cases layout_decl does not handle. */ - if (DECL_BIT_FIELD (field) && !STRICT_ALIGNMENT - && value_factor_p (pos, BITS_PER_UNIT) + if (DECL_BIT_FIELD (field) && operand_equal_p (this_size, TYPE_SIZE (type), 0)) - DECL_BIT_FIELD (field) = 0; + { + unsigned int align = TYPE_ALIGN (type); + + /* In the general case, type alignment is required. */ + if (value_factor_p (pos, align)) + { + /* The enclosing record type must be sufficiently aligned. + Otherwise, if no alignment was specified for it and it + has been laid out already, bump its alignment to the + desired one if this is compatible with its size. */ + if (TYPE_ALIGN (record_type) >= align) + { + DECL_ALIGN (field) = MAX (DECL_ALIGN (field), align); + DECL_BIT_FIELD (field) = 0; + } + else if (!had_align + && rep_level == 0 + && value_factor_p (TYPE_SIZE (record_type), align)) + { + TYPE_ALIGN (record_type) = align; + DECL_ALIGN (field) = MAX (DECL_ALIGN (field), align); + DECL_BIT_FIELD (field) = 0; + } + } + + /* In the non-strict alignment case, only byte alignment is. */ + if (!STRICT_ALIGNMENT + && DECL_BIT_FIELD (field) + && value_factor_p (pos, BITS_PER_UNIT)) + DECL_BIT_FIELD (field) = 0; + } /* If we still have DECL_BIT_FIELD set at this point, we know the field is technically not addressable. Except that it can actually be @@ -830,7 +862,9 @@ finish_record_type (tree record_type, tree fieldlist, int rep_level, DECL_NONADDRESSABLE_P (field) |= DECL_BIT_FIELD (field) && DECL_MODE (field) != BLKmode; - if ((rep_level > 0) && !DECL_BIT_FIELD (field)) + /* A type must be as aligned as its most aligned field that is not + a bit-field. But this is already enforced by layout_type. */ + if (rep_level > 0 && !DECL_BIT_FIELD (field)) TYPE_ALIGN (record_type) = MAX (TYPE_ALIGN (record_type), DECL_ALIGN (field)); @@ -1800,7 +1834,7 @@ value_factor_p (tree value, HOST_WIDE_INT factor) return (value_factor_p (TREE_OPERAND (value, 0), factor) || value_factor_p (TREE_OPERAND (value, 1), factor)); - return 0; + return false; } /* Given 2 consecutive field decls PREV_FIELD and CURR_FIELD, return true diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 64896b804ef..4915a4229f2 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,7 @@ +2008-03-08 Eric Botcazou + + * gnat.dg/pack4.adb: New test. + 2008-03-08 Eric Botcazou * gnat.dg/small_alignment.adb: New test. diff --git a/gcc/testsuite/gnat.dg/pack4.adb b/gcc/testsuite/gnat.dg/pack4.adb new file mode 100644 index 00000000000..2c73e1dd4ea --- /dev/null +++ b/gcc/testsuite/gnat.dg/pack4.adb @@ -0,0 +1,38 @@ +-- { dg-do run } + +procedure Pack4 is + + type Time_T is record + Hour : Integer; + end record; + + type Date_And_Time_T is record + Date : Integer; + Time : Time_T; + end record; + + pragma Pack(Date_And_Time_T); + + procedure + Assign_Hour_Of (T : out Time_T) + is + begin + T.Hour := 44; + end; + + procedure + Clobber_Hour_Of (DT: out Date_And_Time_T) + is + begin + Assign_Hour_Of (Dt.Time); + end; + + DT : Date_And_Time_T; + +begin + DT.Time.Hour := 22; + Clobber_Hour_Of (DT); + if DT.Time.Hour /= 44 then + raise Program_Error; + end if; +end; -- 2.30.2