Commit b1a785fb by Eric Botcazou Committed by Eric Botcazou

decl.c (gnat_to_gnu_entity): Adjust call to components_to_record.

	* gcc-interface/decl.c (gnat_to_gnu_entity) <E_Record_Type>: Adjust
	call to components_to_record.
	(components_to_record): Add FIRST_FREE_POS parameter.  For the variant
	part, reuse enclosing union even if there is a representation clause
	on the Unchecked_Union.  If there is a variant part, compute the new
	first free position, if any.  Adjust call to self.  Use a single field
	directly only if it hasn't got a representation clause or is placed at
	offset zero.  Create the variant part at offset 0 if all the fields
	down to this level have a rep clause.  Do not chain the variant part
	immediately and adjust downstream.
	Do not test ALL_REP before moving the fields without rep clause to the
	previous level.  Call create_rep_part to create the REP part and force
	a minimum size on it if necessary.  Do not chain it immediately.
	Create a fake REP part if there are fields without rep clause that need
	to be laid out starting from FIRST_FREE_POS.
	At the end, chain the REP part and then the variant part.
	(create_rep_part): New function.
	(get_rep_part): Minor tweak.
	* gcc-interface/utils.c (tree_code_for_record_type): Minor tweak.

From-SVN: r181526
parent 40760111
2011-11-20 Eric Botcazou <ebotcazou@adacore.com>
* gcc-interface/decl.c (gnat_to_gnu_entity) <E_Record_Type>: Adjust
call to components_to_record.
(components_to_record): Add FIRST_FREE_POS parameter. For the variant
part, reuse enclosing union even if there is a representation clause
on the Unchecked_Union. If there is a variant part, compute the new
first free position, if any. Adjust call to self. Use a single field
directly only if it hasn't got a representation clause or is placed at
offset zero. Create the variant part at offset 0 if all the fields
down to this level have a rep clause. Do not chain the variant part
immediately and adjust downstream.
Do not test ALL_REP before moving the fields without rep clause to the
previous level. Call create_rep_part to create the REP part and force
a minimum size on it if necessary. Do not chain it immediately.
Create a fake REP part if there are fields without rep clause that need
to be laid out starting from FIRST_FREE_POS.
At the end, chain the REP part and then the variant part.
(create_rep_part): New function.
(get_rep_part): Minor tweak.
* gcc-interface/utils.c (tree_code_for_record_type): Minor tweak.
2011-11-18 Iain Sandoe <iains@gcc.gnu.org> 2011-11-18 Iain Sandoe <iains@gcc.gnu.org>
PR target/50678 PR target/50678
......
...@@ -160,7 +160,7 @@ static bool compile_time_known_address_p (Node_Id); ...@@ -160,7 +160,7 @@ static bool compile_time_known_address_p (Node_Id);
static bool cannot_be_superflat_p (Node_Id); static bool cannot_be_superflat_p (Node_Id);
static bool constructor_address_p (tree); static bool constructor_address_p (tree);
static void components_to_record (tree, Node_Id, tree, int, bool, bool, bool, static void components_to_record (tree, Node_Id, tree, int, bool, bool, bool,
bool, bool, bool, bool, tree *); bool, bool, bool, bool, tree, tree *);
static Uint annotate_value (tree); static Uint annotate_value (tree);
static void annotate_rep (Entity_Id, tree); static void annotate_rep (Entity_Id, tree);
static tree build_position_list (tree, bool, tree, tree, unsigned int, tree); static tree build_position_list (tree, bool, tree, tree, unsigned int, tree);
...@@ -176,6 +176,7 @@ static unsigned int ceil_alignment (unsigned HOST_WIDE_INT); ...@@ -176,6 +176,7 @@ static unsigned int ceil_alignment (unsigned HOST_WIDE_INT);
static void check_ok_for_atomic (tree, Entity_Id, bool); static void check_ok_for_atomic (tree, Entity_Id, bool);
static tree create_field_decl_from (tree, tree, tree, tree, tree, static tree create_field_decl_from (tree, tree, tree, tree, tree,
VEC(subst_pair,heap) *); VEC(subst_pair,heap) *);
static tree create_rep_part (tree, tree, tree);
static tree get_rep_part (tree); static tree get_rep_part (tree);
static tree create_variant_part_from (tree, VEC(variant_desc,heap) *, tree, static tree create_variant_part_from (tree, VEC(variant_desc,heap) *, tree,
tree, VEC(subst_pair,heap) *); tree, VEC(subst_pair,heap) *);
...@@ -3048,7 +3049,7 @@ gnat_to_gnu_entity (Entity_Id gnat_entity, tree gnu_expr, int definition) ...@@ -3048,7 +3049,7 @@ gnat_to_gnu_entity (Entity_Id gnat_entity, tree gnu_expr, int definition)
gnu_field_list, packed, definition, false, gnu_field_list, packed, definition, false,
all_rep, is_unchecked_union, debug_info_p, all_rep, is_unchecked_union, debug_info_p,
false, OK_To_Reorder_Components (gnat_entity), false, OK_To_Reorder_Components (gnat_entity),
NULL); all_rep ? NULL_TREE : bitsize_zero_node, NULL);
/* If it is passed by reference, force BLKmode to ensure that objects /* If it is passed by reference, force BLKmode to ensure that objects
of this type will always be put in memory. */ of this type will always be put in memory. */
...@@ -7096,6 +7097,10 @@ compare_field_bitpos (const PTR rt1, const PTR rt2) ...@@ -7096,6 +7097,10 @@ compare_field_bitpos (const PTR rt1, const PTR rt2)
REORDER is true if we are permitted to reorder components of this type. REORDER is true if we are permitted to reorder components of this type.
FIRST_FREE_POS, if nonzero, is the first (lowest) free field position in
the outer record type down to this variant level. It is nonzero only if
all the fields down to this level have a rep clause and ALL_REP is false.
P_GNU_REP_LIST, if nonzero, is a pointer to a list to which each field P_GNU_REP_LIST, if nonzero, is a pointer to a list to which each field
with a rep clause is to be added; in this case, that is all that should with a rep clause is to be added; in this case, that is all that should
be done with such fields. */ be done with such fields. */
...@@ -7106,12 +7111,13 @@ components_to_record (tree gnu_record_type, Node_Id gnat_component_list, ...@@ -7106,12 +7111,13 @@ components_to_record (tree gnu_record_type, Node_Id gnat_component_list,
bool cancel_alignment, bool all_rep, bool cancel_alignment, bool all_rep,
bool unchecked_union, bool debug_info, bool unchecked_union, bool debug_info,
bool maybe_unused, bool reorder, bool maybe_unused, bool reorder,
tree *p_gnu_rep_list) tree first_free_pos, tree *p_gnu_rep_list)
{ {
bool all_rep_and_size = all_rep && TYPE_SIZE (gnu_record_type); bool all_rep_and_size = all_rep && TYPE_SIZE (gnu_record_type);
bool layout_with_rep = false; bool layout_with_rep = false;
Node_Id component_decl, variant_part; Node_Id component_decl, variant_part;
tree gnu_field, gnu_next, gnu_last; tree gnu_field, gnu_next, gnu_last;
tree gnu_rep_part = NULL_TREE;
tree gnu_variant_part = NULL_TREE; tree gnu_variant_part = NULL_TREE;
tree gnu_rep_list = NULL_TREE; tree gnu_rep_list = NULL_TREE;
tree gnu_var_list = NULL_TREE; tree gnu_var_list = NULL_TREE;
...@@ -7185,7 +7191,7 @@ components_to_record (tree gnu_record_type, Node_Id gnat_component_list, ...@@ -7185,7 +7191,7 @@ components_to_record (tree gnu_record_type, Node_Id gnat_component_list,
= concat_name (get_identifier (Get_Name_String (Chars (gnat_discr))), = concat_name (get_identifier (Get_Name_String (Chars (gnat_discr))),
"XVN"); "XVN");
tree gnu_union_type, gnu_union_name; tree gnu_union_type, gnu_union_name;
tree gnu_variant_list = NULL_TREE; tree this_first_free_pos, gnu_variant_list = NULL_TREE;
if (TREE_CODE (gnu_name) == TYPE_DECL) if (TREE_CODE (gnu_name) == TYPE_DECL)
gnu_name = DECL_NAME (gnu_name); gnu_name = DECL_NAME (gnu_name);
...@@ -7193,12 +7199,10 @@ components_to_record (tree gnu_record_type, Node_Id gnat_component_list, ...@@ -7193,12 +7199,10 @@ components_to_record (tree gnu_record_type, Node_Id gnat_component_list,
gnu_union_name gnu_union_name
= concat_name (gnu_name, IDENTIFIER_POINTER (gnu_var_name)); = concat_name (gnu_name, IDENTIFIER_POINTER (gnu_var_name));
/* Reuse an enclosing union if all fields are in the variant part /* Reuse the enclosing union if this is an Unchecked_Union whose fields
and there is no representation clause on the record, to match are all in the variant part, to match the layout of C unions. There
the layout of C unions. There is an associated check below. */ is an associated check below. */
if (!gnu_field_list if (TREE_CODE (gnu_record_type) == UNION_TYPE)
&& TREE_CODE (gnu_record_type) == UNION_TYPE
&& !TYPE_PACKED (gnu_record_type))
gnu_union_type = gnu_record_type; gnu_union_type = gnu_record_type;
else else
{ {
...@@ -7210,6 +7214,29 @@ components_to_record (tree gnu_record_type, Node_Id gnat_component_list, ...@@ -7210,6 +7214,29 @@ components_to_record (tree gnu_record_type, Node_Id gnat_component_list,
TYPE_PACKED (gnu_union_type) = TYPE_PACKED (gnu_record_type); TYPE_PACKED (gnu_union_type) = TYPE_PACKED (gnu_record_type);
} }
/* If all the fields down to this level have a rep clause, find out
whether all the fields at this level also have one. If so, then
compute the new first free position to be passed downward. */
this_first_free_pos = first_free_pos;
if (this_first_free_pos)
{
for (gnu_field = gnu_field_list;
gnu_field;
gnu_field = DECL_CHAIN (gnu_field))
if (DECL_FIELD_OFFSET (gnu_field))
{
tree pos = bit_position (gnu_field);
if (!tree_int_cst_lt (pos, this_first_free_pos))
this_first_free_pos
= size_binop (PLUS_EXPR, pos, DECL_SIZE (gnu_field));
}
else
{
this_first_free_pos = NULL_TREE;
break;
}
}
for (variant = First_Non_Pragma (Variants (variant_part)); for (variant = First_Non_Pragma (Variants (variant_part));
Present (variant); Present (variant);
variant = Next_Non_Pragma (variant)) variant = Next_Non_Pragma (variant))
...@@ -7231,8 +7258,7 @@ components_to_record (tree gnu_record_type, Node_Id gnat_component_list, ...@@ -7231,8 +7258,7 @@ components_to_record (tree gnu_record_type, Node_Id gnat_component_list,
TYPE_PACKED (gnu_variant_type) = TYPE_PACKED (gnu_record_type); TYPE_PACKED (gnu_variant_type) = TYPE_PACKED (gnu_record_type);
/* Similarly, if the outer record has a size specified and all /* Similarly, if the outer record has a size specified and all
fields have record rep clauses, we can propagate the size the fields have a rep clause, we can propagate the size. */
into the variant part. */
if (all_rep_and_size) if (all_rep_and_size)
{ {
TYPE_SIZE (gnu_variant_type) = TYPE_SIZE (gnu_record_type); TYPE_SIZE (gnu_variant_type) = TYPE_SIZE (gnu_record_type);
...@@ -7244,20 +7270,24 @@ components_to_record (tree gnu_record_type, Node_Id gnat_component_list, ...@@ -7244,20 +7270,24 @@ components_to_record (tree gnu_record_type, Node_Id gnat_component_list,
we aren't sure to really use it at this point, see below. */ we aren't sure to really use it at this point, see below. */
components_to_record (gnu_variant_type, Component_List (variant), components_to_record (gnu_variant_type, Component_List (variant),
NULL_TREE, packed, definition, NULL_TREE, packed, definition,
!all_rep_and_size, all_rep, !all_rep_and_size, all_rep, unchecked_union,
unchecked_union, debug_info, debug_info, true, reorder, this_first_free_pos,
true, reorder, &gnu_rep_list); all_rep || this_first_free_pos
? NULL : &gnu_rep_list);
gnu_qual = choices_to_gnu (gnu_discr, Discrete_Choices (variant)); gnu_qual = choices_to_gnu (gnu_discr, Discrete_Choices (variant));
Set_Present_Expr (variant, annotate_value (gnu_qual)); Set_Present_Expr (variant, annotate_value (gnu_qual));
/* If this is an Unchecked_Union and we have exactly one field, /* If this is an Unchecked_Union whose fields are all in the variant
use this field directly to match the layout of C unions. */ part and we have a single field with no representation clause or
if (unchecked_union placed at offset zero, use the field directly to match the layout
&& TYPE_FIELDS (gnu_variant_type) of C unions. */
&& !DECL_CHAIN (TYPE_FIELDS (gnu_variant_type))) if (TREE_CODE (gnu_record_type) == UNION_TYPE
gnu_field = TYPE_FIELDS (gnu_variant_type); && (gnu_field = TYPE_FIELDS (gnu_variant_type)) != NULL_TREE
&& !DECL_CHAIN (gnu_field)
&& (!DECL_FIELD_OFFSET (gnu_field)
|| integer_zerop (bit_position (gnu_field))))
DECL_CONTEXT (gnu_field) = gnu_union_type;
else else
{ {
/* Deal with packedness like in gnat_to_gnu_field. */ /* Deal with packedness like in gnat_to_gnu_field. */
...@@ -7328,15 +7358,18 @@ components_to_record (tree gnu_record_type, Node_Id gnat_component_list, ...@@ -7328,15 +7358,18 @@ components_to_record (tree gnu_record_type, Node_Id gnat_component_list,
gnu_variant_part gnu_variant_part
= create_field_decl (gnu_var_name, gnu_union_type, gnu_record_type, = create_field_decl (gnu_var_name, gnu_union_type, gnu_record_type,
all_rep ? TYPE_SIZE (gnu_union_type) : 0, all_rep ? TYPE_SIZE (gnu_union_type) : 0,
all_rep ? bitsize_zero_node : 0, all_rep || this_first_free_pos
? bitsize_zero_node : 0,
union_field_packed, 0); union_field_packed, 0);
DECL_INTERNAL_P (gnu_variant_part) = 1; DECL_INTERNAL_P (gnu_variant_part) = 1;
DECL_CHAIN (gnu_variant_part) = gnu_field_list;
gnu_field_list = gnu_variant_part;
} }
} }
/* From now on, a zero FIRST_FREE_POS is totally useless. */
if (first_free_pos && integer_zerop (first_free_pos))
first_free_pos = NULL_TREE;
/* Scan GNU_FIELD_LIST and see if any fields have rep clauses and, if we are /* Scan GNU_FIELD_LIST and see if any fields have rep clauses and, if we are
permitted to reorder components, self-referential sizes or variable sizes. permitted to reorder components, self-referential sizes or variable sizes.
If they do, pull them out and put them onto the appropriate list. We have If they do, pull them out and put them onto the appropriate list. We have
...@@ -7368,17 +7401,9 @@ components_to_record (tree gnu_record_type, Node_Id gnat_component_list, ...@@ -7368,17 +7401,9 @@ components_to_record (tree gnu_record_type, Node_Id gnat_component_list,
continue; continue;
} }
if (reorder) /* Reorder non-internal fields with non-fixed size. */
{ if (reorder
/* Pull out the variant part and put it onto GNU_SELF_LIST. */ && !DECL_INTERNAL_P (gnu_field)
if (gnu_field == gnu_variant_part)
{
MOVE_FROM_FIELD_LIST_TO (gnu_self_list);
continue;
}
/* Skip internal fields and fields with fixed size. */
if (!DECL_INTERNAL_P (gnu_field)
&& !(DECL_SIZE (gnu_field) && !(DECL_SIZE (gnu_field)
&& TREE_CODE (DECL_SIZE (gnu_field)) == INTEGER_CST)) && TREE_CODE (DECL_SIZE (gnu_field)) == INTEGER_CST))
{ {
...@@ -7396,7 +7421,6 @@ components_to_record (tree gnu_record_type, Node_Id gnat_component_list, ...@@ -7396,7 +7421,6 @@ components_to_record (tree gnu_record_type, Node_Id gnat_component_list,
continue; continue;
} }
} }
}
gnu_last = gnu_field; gnu_last = gnu_field;
} }
...@@ -7416,14 +7440,14 @@ components_to_record (tree gnu_record_type, Node_Id gnat_component_list, ...@@ -7416,14 +7440,14 @@ components_to_record (tree gnu_record_type, Node_Id gnat_component_list,
= chainon (nreverse (gnu_self_list), = chainon (nreverse (gnu_self_list),
chainon (nreverse (gnu_var_list), gnu_field_list)); chainon (nreverse (gnu_var_list), gnu_field_list));
/* If we have any fields in our rep'ed field list and it is not the case that /* If P_REP_LIST is nonzero, this means that we are asked to move the fields
all the fields in the record have rep clauses and P_REP_LIST is nonzero, in our REP list to the previous level because this level needs them in
set it and ignore these fields. */ order to do a correct layout, i.e. avoid having overlapping fields. */
if (gnu_rep_list && p_gnu_rep_list && !all_rep) if (p_gnu_rep_list && gnu_rep_list)
*p_gnu_rep_list = chainon (*p_gnu_rep_list, gnu_rep_list); *p_gnu_rep_list = chainon (*p_gnu_rep_list, gnu_rep_list);
/* Otherwise, sort the fields by bit position and put them into their own /* Otherwise, sort the fields by bit position and put them into their own
record, before the others, if we also have fields without rep clauses. */ record, before the others, if we also have fields without rep clause. */
else if (gnu_rep_list) else if (gnu_rep_list)
{ {
tree gnu_rep_type tree gnu_rep_type
...@@ -7451,11 +7475,12 @@ components_to_record (tree gnu_record_type, Node_Id gnat_component_list, ...@@ -7451,11 +7475,12 @@ components_to_record (tree gnu_record_type, Node_Id gnat_component_list,
if (gnu_field_list) if (gnu_field_list)
{ {
finish_record_type (gnu_rep_type, gnu_rep_list, 1, debug_info); finish_record_type (gnu_rep_type, gnu_rep_list, 1, debug_info);
gnu_field
= create_field_decl (get_identifier ("REP"), gnu_rep_type, /* If FIRST_FREE_POS is nonzero, we need to ensure that the fields
gnu_record_type, NULL_TREE, NULL_TREE, 0, 1); without rep clause are laid out starting from this position.
DECL_INTERNAL_P (gnu_field) = 1; Therefore, we force it as a minimal size on the REP part. */
gnu_field_list = chainon (gnu_field_list, gnu_field); gnu_rep_part
= create_rep_part (gnu_rep_type, gnu_record_type, first_free_pos);
} }
else else
{ {
...@@ -7464,6 +7489,28 @@ components_to_record (tree gnu_record_type, Node_Id gnat_component_list, ...@@ -7464,6 +7489,28 @@ components_to_record (tree gnu_record_type, Node_Id gnat_component_list,
} }
} }
/* If FIRST_FREE_POS is nonzero, we need to ensure that the fields without
rep clause are laid out starting from this position. Therefore, if we
have not already done so, we create a fake REP part with this size. */
if (first_free_pos && !layout_with_rep && !gnu_rep_part)
{
tree gnu_rep_type = make_node (RECORD_TYPE);
finish_record_type (gnu_rep_type, NULL_TREE, 0, debug_info);
gnu_rep_part
= create_rep_part (gnu_rep_type, gnu_record_type, first_free_pos);
}
/* Now chain the REP part at the end of the reversed field list. */
if (gnu_rep_part)
gnu_field_list = chainon (gnu_field_list, gnu_rep_part);
/* And the variant part at the beginning. */
if (gnu_variant_part)
{
DECL_CHAIN (gnu_variant_part) = gnu_field_list;
gnu_field_list = gnu_variant_part;
}
if (cancel_alignment) if (cancel_alignment)
TYPE_ALIGN (gnu_record_type) = 0; TYPE_ALIGN (gnu_record_type) = 0;
...@@ -8567,6 +8614,24 @@ create_field_decl_from (tree old_field, tree field_type, tree record_type, ...@@ -8567,6 +8614,24 @@ create_field_decl_from (tree old_field, tree field_type, tree record_type,
return new_field; return new_field;
} }
/* Create the REP part of RECORD_TYPE with REP_TYPE. If MIN_SIZE is nonzero,
it is the minimal size the REP_PART must have. */
static tree
create_rep_part (tree rep_type, tree record_type, tree min_size)
{
tree field;
if (min_size && !tree_int_cst_lt (TYPE_SIZE (rep_type), min_size))
min_size = NULL_TREE;
field = create_field_decl (get_identifier ("REP"), rep_type, record_type,
min_size, bitsize_zero_node, 0, 1);
DECL_INTERNAL_P (field) = 1;
return field;
}
/* Return the REP part of RECORD_TYPE, if any. Otherwise return NULL. */ /* Return the REP part of RECORD_TYPE, if any. Otherwise return NULL. */
static tree static tree
...@@ -8575,10 +8640,10 @@ get_rep_part (tree record_type) ...@@ -8575,10 +8640,10 @@ get_rep_part (tree record_type)
tree field = TYPE_FIELDS (record_type); tree field = TYPE_FIELDS (record_type);
/* The REP part is the first field, internal, another record, and its name /* The REP part is the first field, internal, another record, and its name
doesn't start with an underscore (i.e. is not generated by the FE). */ starts with an 'R'. */
if (DECL_INTERNAL_P (field) if (DECL_INTERNAL_P (field)
&& TREE_CODE (TREE_TYPE (field)) == RECORD_TYPE && TREE_CODE (TREE_TYPE (field)) == RECORD_TYPE
&& IDENTIFIER_POINTER (DECL_NAME (field)) [0] != '_') && IDENTIFIER_POINTER (DECL_NAME (field)) [0] == 'R')
return field; return field;
return NULL_TREE; return NULL_TREE;
......
...@@ -4744,19 +4744,17 @@ unchecked_convert (tree type, tree expr, bool notrunc_p) ...@@ -4744,19 +4744,17 @@ unchecked_convert (tree type, tree expr, bool notrunc_p)
enum tree_code enum tree_code
tree_code_for_record_type (Entity_Id gnat_type) tree_code_for_record_type (Entity_Id gnat_type)
{ {
Node_Id component_list Node_Id component_list, component;
= Component_List (Type_Definition
(Declaration_Node
(Implementation_Base_Type (gnat_type))));
Node_Id component;
/* Make this a UNION_TYPE unless it's either not an Unchecked_Union or
we have a non-discriminant field outside a variant. In either case,
it's a RECORD_TYPE. */
/* Return UNION_TYPE if it's an Unchecked_Union whose non-discriminant
fields are all in the variant part. Otherwise, return RECORD_TYPE. */
if (!Is_Unchecked_Union (gnat_type)) if (!Is_Unchecked_Union (gnat_type))
return RECORD_TYPE; return RECORD_TYPE;
gnat_type = Implementation_Base_Type (gnat_type);
component_list
= Component_List (Type_Definition (Declaration_Node (gnat_type)));
for (component = First_Non_Pragma (Component_Items (component_list)); for (component = First_Non_Pragma (Component_Items (component_list));
Present (component); Present (component);
component = Next_Non_Pragma (component)) component = Next_Non_Pragma (component))
......
2011-11-20 Eric Botcazou <ebotcazou@adacore.com>
* gnat.dg/discr32.adb: New test.
* gnat.dg/discr32_pkg.ads: New helper.
2011-11-20 Nathan Sidwell <nathan@acm.org> 2011-11-20 Nathan Sidwell <nathan@acm.org>
PR gcov-profile/51113 PR gcov-profile/51113
......
-- { dg-do run }
-- { dg-options "-gnatws" }
with Discr32_Pkg; use Discr32_Pkg;
procedure Discr32 is
begin
if R1'Object_Size /= 32 then
raise Program_Error;
end if;
if R2'Object_Size /= R'Object_Size then
raise Program_Error;
end if;
if R3'Object_Size /= 64 then
raise Program_Error;
end if;
end;
package Discr32_Pkg is
type Enum is (One, Two, Three);
type R (D : Enum) is record
case D is
when One => B : Boolean;
when Two => I : Integer;
when Three => F : Float;
end case;
end record;
for R use record
D at 0 range 0 .. 1;
B at 1 range 0 .. 0;
I at 4 range 0 .. 31 + 128;
-- F at 4 range 0 .. 31;
end record;
subtype R1 is R (One);
subtype R2 is R (Two);
subtype R3 is R (Three);
end Discr32_Pkg;
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment