This repairs the ABI breakage for record types with Long_Float components
introduced on 32-bit x86/Linux by the previous change. The Long_Float type
is awkward on this platform because it has got a dual alignment setting:
it's 8 for standalone object and array component and 4 for record component.
Since Ada defines a single 'Alignment value, it is set to 4 and there is a
special circuitry in Set_Elem_Alignment to implement it.
The previous change short-circuited Set_Elem_Alignment in Build_Float_Type,
which resulted in a Long_Float'Alignment value of 8.
The following package:
package P is
type Rec is record
I : Integer;
F : Long_Float;
end record;
end P;
must yield the following output when compiled with -gnatR2 on 32-bit Linux:
Representation information for unit P (spec)
for Rec'Size use 96;
for Rec'Alignment use 4;
for Rec use record
I at 0 range 0 .. 31;
F at 4 range 0 .. 63;
end record;
Tested on x86_64-pc-linux-gnu, committed on trunk
2017-10-14 Eric Botcazou <[email protected]>
* layout.ads (Set_Elem_Alignment): Add Align parameter defaulted to 0.
* layout.adb (Set_Elem_Alignment): Likewise. Use M name as maximum
alignment for consistency. If Align is non-zero, use the minimum of
Align and M for the alignment.
* cstand.adb (Build_Float_Type): Use Set_Elem_Alignment instead of
setting the alignment directly.
Index: cstand.adb
===================================================================
--- cstand.adb (revision 253756)
+++ cstand.adb (working copy)
@@ -212,7 +212,7 @@
Init_Digits_Value (E, Digs);
Set_Float_Rep (E, Rep);
Init_Size (E, Siz);
- Set_Alignment (E, UI_From_Int (Align));
+ Set_Elem_Alignment (E, Align);
Set_Float_Bounds (E);
Set_Is_Frozen (E);
Set_Is_Public (E);
Index: layout.adb
===================================================================
--- layout.adb (revision 253753)
+++ layout.adb (working copy)
@@ -843,7 +843,7 @@
-- Set_Elem_Alignment --
------------------------
- procedure Set_Elem_Alignment (E : Entity_Id) is
+ procedure Set_Elem_Alignment (E : Entity_Id; Align : Nat := 0) is
begin
-- Do not set alignment for packed array types, this is handled in the
-- backend.
@@ -869,16 +869,13 @@
return;
end if;
- -- Here we calculate the alignment as the largest power of two multiple
- -- of System.Storage_Unit that does not exceed either the object size of
- -- the type, or the maximum allowed alignment.
+ -- We attempt to set the alignment in all the other cases
declare
S : Int;
A : Nat;
+ M : Nat;
- Max_Alignment : Nat;
-
begin
-- The given Esize may be larger that int'last because of a previous
-- error, and the call to UI_To_Int will fail, so use default.
@@ -908,7 +905,7 @@
and then S = 8
and then Is_Floating_Point_Type (E)
then
- Max_Alignment := Ttypes.Target_Double_Float_Alignment;
+ M := Ttypes.Target_Double_Float_Alignment;
-- If the default alignment of "double" or larger scalar types is
-- specifically capped, enforce the cap.
@@ -917,19 +914,28 @@
and then S >= 8
and then Is_Scalar_Type (E)
then
- Max_Alignment := Ttypes.Target_Double_Scalar_Alignment;
+ M := Ttypes.Target_Double_Scalar_Alignment;
-- Otherwise enforce the overall alignment cap
else
- Max_Alignment := Ttypes.Maximum_Alignment;
+ M := Ttypes.Maximum_Alignment;
end if;
- A := 1;
- while 2 * A <= Max_Alignment and then 2 * A <= S loop
- A := 2 * A;
- end loop;
+ -- We calculate the alignment as the largest power-of-two multiple
+ -- of System.Storage_Unit that does not exceed the object size of
+ -- the type and the maximum allowed alignment, if none was specified.
+ -- Otherwise we only cap it to the maximum allowed alignment.
+ if Align = 0 then
+ A := 1;
+ while 2 * A <= S and then 2 * A <= M loop
+ A := 2 * A;
+ end loop;
+ else
+ A := Nat'Min (Align, M);
+ end if;
+
-- If alignment is currently not set, then we can safely set it to
-- this new calculated value.
Index: layout.ads
===================================================================
--- layout.ads (revision 253753)
+++ layout.ads (working copy)
@@ -74,10 +74,11 @@
-- types, the RM_Size is simply set to zero. This routine also sets
-- the Is_Constrained flag in Def_Id.
- procedure Set_Elem_Alignment (E : Entity_Id);
+ procedure Set_Elem_Alignment (E : Entity_Id; Align : Nat := 0);
-- The front end always sets alignments for elementary types by calling
-- this procedure. Note that we have to do this for discrete types (since
-- the Alignment attribute is static), so we might as well do it for all
- -- elementary types, since the processing is the same.
+ -- elementary types, as the processing is the same. If Align is nonzero,
+ -- it is an external alignment setting that we must respect.
end Layout;