exp_util.adb (Remove_Side_Effects): Also make a constant if we need to capture the value for a small not...

* exp_util.adb (Remove_Side_Effects): Also make a constant if we need
	to capture the value for a small not by-reference record type.
	* freeze.ads (Check_Compile_Time_Size): Adjust comment.
	* freeze.adb (Set_Small_Size): Likewise.  Accept a size in the range
	of 33 .. 64 bits.
	(Check_Compile_Time_Size): Merge scalar and access type cases. Change
	variable name in array type case.  For the computation of the packed
	size, deal with record components and remove redundant test.
	(Freeze_Array_Type): Also adjust packing status when the size of the
	component type is in the range 33 .. 64 bits.
	* doc/gnat_rm/representation_clauses_and_pragmas.rst: Turn primitive
	into elementary type throughout.  Minor tweaks.
	(Alignment Clauses): Document actual alignment of packed array types.
	(Pragma Pack for Arrays): List only the 3 main cases and adjust.  Add
	"simple" to the record case.  Document effect on non packable types.
	(Pragma Pack for Records): Likewise.  Add record case and adjust.

From-SVN: r236275
This commit is contained in:
Eric Botcazou 2016-05-16 10:14:19 +00:00 committed by Eric Botcazou
parent 0b9004ed56
commit 34da9c9840
5 changed files with 102 additions and 102 deletions

View File

@ -1,3 +1,22 @@
2016-05-16 Eric Botcazou <ebotcazou@adacore.com>
* exp_util.adb (Remove_Side_Effects): Also make a constant if we need
to capture the value for a small not by-reference record type.
* freeze.ads (Check_Compile_Time_Size): Adjust comment.
* freeze.adb (Set_Small_Size): Likewise. Accept a size in the range
of 33 .. 64 bits.
(Check_Compile_Time_Size): Merge scalar and access type cases. Change
variable name in array type case. For the computation of the packed
size, deal with record components and remove redundant test.
(Freeze_Array_Type): Also adjust packing status when the size of the
component type is in the range 33 .. 64 bits.
* doc/gnat_rm/representation_clauses_and_pragmas.rst: Turn primitive
into elementary type throughout. Minor tweaks.
(Alignment Clauses): Document actual alignment of packed array types.
(Pragma Pack for Arrays): List only the 3 main cases and adjust. Add
"simple" to the record case. Document effect on non packable types.
(Pragma Pack for Records): Likewise. Add record case and adjust.
2016-05-16 Eric Botcazou <ebotcazou@adacore.com> 2016-05-16 Eric Botcazou <ebotcazou@adacore.com>
* gcc-interface/Make-lang.in (GNATMAKE_FOR_HOST): In the canadian * gcc-interface/Make-lang.in (GNATMAKE_FOR_HOST): In the canadian

View File

@ -32,9 +32,9 @@ GNAT requires that all alignment clauses specify a power of 2, and all
default alignments are always a power of 2. The default alignment default alignments are always a power of 2. The default alignment
values are as follows: values are as follows:
* *Primitive Types*. * *Elementary Types*.
For primitive types, the alignment is the minimum of the actual size of For elementary types, the alignment is the minimum of the actual size of
objects of the type divided by `Storage_Unit`, objects of the type divided by `Storage_Unit`,
and the maximum alignment supported by the target. and the maximum alignment supported by the target.
(This maximum alignment is given by the GNAT-specific attribute (This maximum alignment is given by the GNAT-specific attribute
@ -53,10 +53,11 @@ values are as follows:
For arrays, the alignment is equal to the alignment of the component type For arrays, the alignment is equal to the alignment of the component type
for the normal case where no packing or component size is given. If the for the normal case where no packing or component size is given. If the
array is packed, and the packing is effective (see separate section on array is packed, and the packing is effective (see separate section on
packed arrays), then the alignment will be one for long packed arrays, packed arrays), then the alignment will be either 4, 2 or 1 for long packed
or arrays whose length is not known at compile time. For short packed arrays or arrays whose length is not known at compile time, depending on
whether the component size is divisible by 4, 2 or is odd. For short packed
arrays, which are handled internally as modular types, the alignment arrays, which are handled internally as modular types, the alignment
will be as described for primitive types, e.g., a packed array of length will be as described for elementary types, e.g. a packed array of length
31 bits will have an object size of four bytes, and an alignment of 4. 31 bits will have an object size of four bytes, and an alignment of 4.
* *Records*. * *Records*.
@ -789,7 +790,7 @@ restrictions placed on component clauses as follows:
little-endian machines, this must be explicitly programmed. This capability little-endian machines, this must be explicitly programmed. This capability
is not provided by `Bit_Order`. is not provided by `Bit_Order`.
* Components that are positioned across byte boundaries * Components that are positioned across byte boundaries.
but do not occupy an integral number of bytes. Given that bytes are not but do not occupy an integral number of bytes. Given that bytes are not
reordered, such fields would occupy a non-contiguous sequence of bits reordered, such fields would occupy a non-contiguous sequence of bits
@ -1069,22 +1070,23 @@ Pragma Pack for Arrays
.. index:: Pragma Pack (for arrays) .. index:: Pragma Pack (for arrays)
Pragma `Pack` applied to an array has no effect unless the component type Pragma `Pack` applied to an array has an effect that depends upon whether the
is packable. For a component type to be packable, it must be one of the component type is *packable*. For a component type to be *packable*, it must
following cases: be one of the following cases:
* * Any elementary type.
Any scalar type
* * Any small packed array type with a static size.
Any type whose size is specified with a size clause
* * Any small simple record type with a static size.
Any packed array type with a static size
*
Any record type padded because of its default alignment
For all these cases, if the component subtype size is in the range For all these cases, if the component subtype size is in the range
1 through 63, then the effect of the pragma `Pack` is exactly as though a 1 through 64, then the effect of the pragma `Pack` is exactly as though a
component size were specified giving the component subtype size. component size were specified giving the component subtype size.
All other types are non-packable, they occupy an integral number of storage
units and the only effect of pragma Pack is to remove alignment gaps.
For example if we have: For example if we have:
.. code-block:: ada .. code-block:: ada
@ -1095,7 +1097,7 @@ For example if we have:
pragma Pack (ar); pragma Pack (ar);
Then the component size of `ar` will be set to 5 (i.e., to `r'size`, Then the component size of `ar` will be set to 5 (i.e., to `r'size`,
and the size of the array `ar` will be exactly 40 bits. and the size of the array `ar` will be exactly 40 bits).
Note that in some cases this rather fierce approach to packing can produce Note that in some cases this rather fierce approach to packing can produce
unexpected effects. For example, in Ada 95 and Ada 2005, unexpected effects. For example, in Ada 95 and Ada 2005,
@ -1184,23 +1186,21 @@ taken by components. We distinguish between *packable* components and
*non-packable* components. *non-packable* components.
Components of the following types are considered packable: Components of the following types are considered packable:
* * Components of an elementary type are packable unless they are aliased,
Components of a primitive type are packable unless they are aliased independent or of an atomic type.
or of an atomic type.
* * Small packed arrays, where the size is statically known, are represented
Small packed arrays, whose size does not exceed 64 bits, and where the internally as modular integers, and so they are also packable.
size is statically known at compile time, are represented internally
as modular integers, and so they are also packable.
* Small simple records, where the size is statically known, are also packable.
All packable components occupy the exact number of bits corresponding to For all these cases, if the 'Size value is in the range 1 through 64, the
their `Size` value, and are packed with no padding bits, i.e., they components occupy the exact number of bits corresponding to this value
can start on an arbitrary bit boundary. and are packed with no padding bits, i.e. they can start on an arbitrary
bit boundary.
All other types are non-packable, they occupy an integral number of All other types are non-packable, they occupy an integral number of storage
storage units, and units and the only effect of pragma Pack is to remove alignment gaps.
are placed at a boundary corresponding to their alignment requirements.
For example, consider the record For example, consider the record
@ -1331,7 +1331,7 @@ so for example, the following is permitted:
Note: the above rules apply to recent releases of GNAT 5. Note: the above rules apply to recent releases of GNAT 5.
In GNAT 3, there are more severe restrictions on larger components. In GNAT 3, there are more severe restrictions on larger components.
For non-primitive types, including packed arrays with a size greater than For composite types, including packed arrays with a size greater than
64 bits, component clauses must respect the alignment requirement of the 64 bits, component clauses must respect the alignment requirement of the
type, in particular, always starting on a byte boundary, and the length type, in particular, always starting on a byte boundary, and the length
must be a multiple of the storage unit. must be a multiple of the storage unit.

View File

@ -7711,15 +7711,22 @@ package body Exp_Util is
Scope_Suppress.Suppress := (others => True); Scope_Suppress.Suppress := (others => True);
-- If it is an elementary type and we need to capture the value, just -- If this is an elementary or a small not by-reference record type, and
-- make a constant. Likewise if this is not a name reference, except -- we need to capture the value, just make a constant; this is cheap and
-- for a type conversion because we would enter an infinite recursion -- objects of both kinds of types can be bit aligned, so it might not be
-- with Checks.Apply_Predicate_Check if the target type has predicates. -- possible to generate a reference to them. Likewise if this is not a
-- And type conversions need a specific treatment anyway, see below. -- name reference, except for a type conversion because we would enter
-- Also do it if we have a volatile reference and Name_Req is not set -- an infinite recursion with Checks.Apply_Predicate_Check if the target
-- (see comments for Side_Effect_Free). -- type has predicates (and type conversions need a specific treatment
-- anyway, see below). Also do it if we have a volatile reference and
-- Name_Req is not set (see comments for Side_Effect_Free).
if Is_Elementary_Type (Exp_Type) if (Is_Elementary_Type (Exp_Type)
or else (Is_Record_Type (Exp_Type)
and then Known_Static_RM_Size (Exp_Type)
and then RM_Size (Exp_Type) <= 64
and then not Has_Discriminants (Exp_Type)
and then not Is_By_Reference_Type (Exp_Type)))
and then (Variable_Ref and then (Variable_Ref
or else (not Is_Name_Reference (Exp) or else (not Is_Name_Reference (Exp)
and then Nkind (Exp) /= N_Type_Conversion) and then Nkind (Exp) /= N_Type_Conversion)

View File

@ -745,9 +745,9 @@ package body Freeze is
procedure Check_Compile_Time_Size (T : Entity_Id) is procedure Check_Compile_Time_Size (T : Entity_Id) is
procedure Set_Small_Size (T : Entity_Id; S : Uint); procedure Set_Small_Size (T : Entity_Id; S : Uint);
-- Sets the compile time known size (32 bits or less) in the Esize -- Sets the compile time known size (64 bits or less) in the RM_Size
-- field, of T checking for a size clause that was given which attempts -- field of T, checking for a size clause that was given which attempts
-- to give a smaller size, and also checking for an alignment clause. -- to give a smaller size.
function Size_Known (T : Entity_Id) return Boolean; function Size_Known (T : Entity_Id) return Boolean;
-- Recursive function that does all the work -- Recursive function that does all the work
@ -765,7 +765,7 @@ package body Freeze is
procedure Set_Small_Size (T : Entity_Id; S : Uint) is procedure Set_Small_Size (T : Entity_Id; S : Uint) is
begin begin
if S > 32 then if S > 64 then
return; return;
-- Check for bad size clause given -- Check for bad size clause given
@ -800,14 +800,12 @@ package body Freeze is
if Size_Known_At_Compile_Time (T) then if Size_Known_At_Compile_Time (T) then
return True; return True;
-- Always True for scalar types. This is true even for generic formal -- Always True for elementary types, even generic formal elementary
-- scalar types. We used to return False in the latter case, but the -- types. We used to return False in the latter case, but the size
-- size is known at compile time, even in the template, we just do -- is known at compile time, even in the template, we just do not
-- not know the exact size but that's not the point of this routine. -- know the exact size but that's not the point of this routine.
elsif Is_Scalar_Type (T) elsif Is_Elementary_Type (T) or else Is_Task_Type (T) then
or else Is_Task_Type (T)
then
return True; return True;
-- Array types -- Array types
@ -817,8 +815,8 @@ package body Freeze is
-- String literals always have known size, and we can set it -- String literals always have known size, and we can set it
if Ekind (T) = E_String_Literal_Subtype then if Ekind (T) = E_String_Literal_Subtype then
Set_Small_Size (T, Component_Size (T) Set_Small_Size
* String_Literal_Length (T)); (T, Component_Size (T) * String_Literal_Length (T));
return True; return True;
-- Unconstrained types never have known at compile time size -- Unconstrained types never have known at compile time size
@ -839,10 +837,10 @@ package body Freeze is
end if; end if;
-- Check for all indexes static, and also compute possible size -- Check for all indexes static, and also compute possible size
-- (in case it is less than 32 and may be packable). -- (in case it is not greater than 64 and may be packable).
declare declare
Esiz : Uint := Component_Size (T); Size : Uint := Component_Size (T);
Dim : Uint; Dim : Uint;
begin begin
@ -869,24 +867,19 @@ package body Freeze is
Dim := Expr_Value (High) - Expr_Value (Low) + 1; Dim := Expr_Value (High) - Expr_Value (Low) + 1;
if Dim >= 0 then if Dim >= 0 then
Esiz := Esiz * Dim; Size := Size * Dim;
else else
Esiz := Uint_0; Size := Uint_0;
end if; end if;
end if; end if;
Next_Index (Index); Next_Index (Index);
end loop; end loop;
Set_Small_Size (T, Esiz); Set_Small_Size (T, Size);
return True; return True;
end; end;
-- Access types always have known at compile time sizes
elsif Is_Access_Type (T) then
return True;
-- For non-generic private types, go to underlying type if present -- For non-generic private types, go to underlying type if present
elsif Is_Private_Type (T) elsif Is_Private_Type (T)
@ -1074,11 +1067,10 @@ package body Freeze is
if Packed_Size_Known then if Packed_Size_Known then
-- We can only deal with elementary types, since for -- We can deal with elementary types, small packed arrays
-- non-elementary components, alignment enters into the -- if the representation is a modular type and also small
-- picture, and we don't know enough to handle proper -- record types (if the size is not greater than 64, but
-- alignment in this context. Packed arrays count as -- the condition is checked by Set_Small_Size).
-- elementary if the representation is a modular type.
if Is_Elementary_Type (Ctyp) if Is_Elementary_Type (Ctyp)
or else (Is_Array_Type (Ctyp) or else (Is_Array_Type (Ctyp)
@ -1086,33 +1078,14 @@ package body Freeze is
(Packed_Array_Impl_Type (Ctyp)) (Packed_Array_Impl_Type (Ctyp))
and then Is_Modular_Integer_Type and then Is_Modular_Integer_Type
(Packed_Array_Impl_Type (Ctyp))) (Packed_Array_Impl_Type (Ctyp)))
or else Is_Record_Type (Ctyp)
then then
-- Packed size unknown if we have an atomic/VFA type
-- or a by-reference type, since the back end knows
-- how these are layed out.
if Is_Atomic_Or_VFA (Ctyp)
or else Is_By_Reference_Type (Ctyp)
then
Packed_Size_Known := False;
-- If RM_Size is known and static, then we can keep -- If RM_Size is known and static, then we can keep
-- accumulating the packed size -- accumulating the packed size.
elsif Known_Static_RM_Size (Ctyp) then if Known_Static_RM_Size (Ctyp) then
-- A little glitch, to be removed sometime ???
-- gigi does not understand zero sizes yet.
if RM_Size (Ctyp) = Uint_0 then
Packed_Size_Known := False;
-- Normal case where we can keep accumulating the
-- packed array size.
else
Packed_Size := Packed_Size + RM_Size (Ctyp); Packed_Size := Packed_Size + RM_Size (Ctyp);
end if;
-- If we have a field whose RM_Size is not known then -- If we have a field whose RM_Size is not known then
-- we can't figure out the packed size here. -- we can't figure out the packed size here.
@ -1121,8 +1094,7 @@ package body Freeze is
Packed_Size_Known := False; Packed_Size_Known := False;
end if; end if;
-- If we have a non-elementary type we can't figure out -- For other types we can't figure out the packed size
-- the packed array size (alignment issues).
else else
Packed_Size_Known := False; Packed_Size_Known := False;
@ -2475,13 +2447,15 @@ package body Freeze is
end if; end if;
-- Actual packing is not needed for 8, 16, 32, 64. Also -- Actual packing is not needed for 8, 16, 32, 64. Also
-- not needed for 24 if alignment is 1. -- not needed for multiples of 8 if alignment is 1, and
-- for multiples of 16 (i.e. only 48) if alignment is 2.
if Csiz = 8 if Csiz = 8
or else Csiz = 16 or else Csiz = 16
or else Csiz = 32 or else Csiz = 32
or else Csiz = 64 or else Csiz = 64
or else (Csiz = 24 and then Alignment (Ctyp) = 1) or else (Csiz mod 8 = 0 and then Alignment (Ctyp) = 1)
or else (Csiz = 48 and then Alignment (Ctyp) = 2)
then then
-- Here the array was requested to be packed, but -- Here the array was requested to be packed, but
-- the packing request had no effect, so Is_Packed -- the packing request had no effect, so Is_Packed

View File

@ -151,15 +151,15 @@ package Freeze is
-- fact Gigi decides it is known, but the opposite situation can never -- fact Gigi decides it is known, but the opposite situation can never
-- occur. -- occur.
-- --
-- Size is known at compile time, but the actual value of the size is -- Size is known at compile time, but the actual value of the size is not
-- not known to the front end or is definitely 32 or more. In this case -- known to the front end or is definitely greater than 64. In this case,
-- Size_Known_At_Compile_Time is set, but the Esize field is left set -- Size_Known_At_Compile_Time is set, but the RM_Size field is left set
-- to zero (to be set by Gigi). -- to zero (to be set by Gigi).
-- --
-- Size is known at compile time, and the actual value of the size is -- Size is known at compile time, and the actual value of the size is
-- known to the front end and is less than 32. In this case, the flag -- known to the front end and is not greater than 64. In this case, the
-- Size_Known_At_Compile_Time is set, and in addition Esize is set to -- flag Size_Known_At_Compile_Time is set, and in addition RM_Size is set
-- the required size, allowing for possible front end packing of an -- to the required size, allowing for possible front end packing of an
-- array using this type as a component type. -- array using this type as a component type.
-- --
-- Note: the flag Size_Known_At_Compile_Time is used to determine if the -- Note: the flag Size_Known_At_Compile_Time is used to determine if the