OSDN Git Service

2008-04-08 Hristian Kirtchev <kirtchev@adacore.com>
[pf3gnuchains/gcc-fork.git] / gcc / ada / layout.adb
index f92a37d..c6dec0a 100644 (file)
@@ -6,7 +6,7 @@
 --                                                                          --
 --                                 B o d y                                  --
 --                                                                          --
---          Copyright (C) 2001-2007, Free Software Foundation, Inc.         --
+--          Copyright (C) 2001-2008, Free Software Foundation, Inc.         --
 --                                                                          --
 -- GNAT is free software;  you can  redistribute it  and/or modify it under --
 -- terms of the  GNU General Public License as published  by the Free Soft- --
@@ -956,7 +956,7 @@ package body Layout is
 
       Make_Size_Function : Boolean := False;
       --  Indicates whether to request that SO_Ref_From_Expr should
-      --  encapsulate the array size expresion in a function.
+      --  encapsulate the array size expression in a function.
 
       procedure Discrimify (N : in out Node_Id);
       --  If N represents a discriminant, then the Size.Status is set to
@@ -2300,6 +2300,8 @@ package body Layout is
    -----------------
 
    procedure Layout_Type (E : Entity_Id) is
+      Desig_Type : Entity_Id;
+
    begin
       --  For string literal types, for now, kill the size always, this
       --  is because gigi does not like or need the size to be set ???
@@ -2321,6 +2323,18 @@ package body Layout is
 
       if Is_Access_Type (E) then
 
+         Desig_Type :=  Underlying_Type (Designated_Type (E));
+
+         --  If we only have a limited view of the type, see whether the
+         --  non-limited view is available.
+
+         if From_With_Type (Designated_Type (E))
+           and then Ekind (Designated_Type (E)) = E_Incomplete_Type
+           and then Present (Non_Limited_View (Designated_Type (E)))
+         then
+            Desig_Type := Non_Limited_View (Designated_Type (E));
+         end if;
+
          --  If Esize already set (e.g. by a size clause), then nothing
          --  further to be done here.
 
@@ -2344,11 +2358,10 @@ package body Layout is
          --  a fat pointer is used (pointer-to-unconstrained array case),
          --  twice the address size to accommodate a fat pointer.
 
-         elsif Present (Underlying_Type (Designated_Type (E)))
-            and then Is_Array_Type (Underlying_Type (Designated_Type (E)))
-            and then not Is_Constrained (Underlying_Type (Designated_Type (E)))
-            and then not Has_Completion_In_Body (Underlying_Type
-                                                 (Designated_Type (E)))
+         elsif Present (Desig_Type)
+            and then Is_Array_Type (Desig_Type)
+            and then not Is_Constrained (Desig_Type)
+            and then not Has_Completion_In_Body (Desig_Type)
             and then not Debug_Flag_6
          then
             Init_Size (E, 2 * System_Address_Size);
@@ -2365,6 +2378,19 @@ package body Layout is
                  ("?this access type does not correspond to C pointer", E);
             end if;
 
+         --  If the designated type is a limited view it is unanalyzed. We
+         --  can examine the declaration itself to determine whether it will
+         --  need a fat pointer.
+
+         elsif Present (Desig_Type)
+            and then Present (Parent (Desig_Type))
+            and then Nkind (Parent (Desig_Type)) = N_Full_Type_Declaration
+            and then
+              Nkind (Type_Definition (Parent (Desig_Type)))
+                 = N_Unconstrained_Array_Definition
+         then
+            Init_Size (E, 2 * System_Address_Size);
+
          --  When the target is AAMP, access-to-subprogram types are fat
          --  pointers consisting of the subprogram address and a static
          --  link (with the exception of library-level access types,
@@ -2395,7 +2421,10 @@ package body Layout is
          --  for this purpose, since it would be weird not to inherit the size
          --  in this case.
 
-         if OpenVMS_On_Target
+         --  We do NOT do this if we are in -gnatdm mode on a non-VMS target
+         --  since in that case we want the normal pointer representation.
+
+         if Opt.True_VMS_Target
            and then (Convention (E) = Convention_C
                       or else
                      Convention (E) = Convention_CPP)
@@ -2461,7 +2490,7 @@ package body Layout is
                end;
             end if;
 
-         --  For non-discrete sclar types, if the RM_Size is not set,
+         --  For non-discrete scalar types, if the RM_Size is not set,
          --  then set it now to a copy of the Esize if the Esize is set.
 
          else
@@ -2562,7 +2591,7 @@ package body Layout is
                Set_Composite_Alignment (E);
             end if;
 
-         --  Procressing for array types
+         --  Processing for array types
 
          elsif Is_Array_Type (E) then
 
@@ -2765,7 +2794,32 @@ package body Layout is
       Align : Nat;
 
    begin
-      if Unknown_Alignment (E) then
+      --  If alignment is already set, then nothing to do
+
+      if Known_Alignment (E) then
+         return;
+      end if;
+
+      --  Alignment is not known, see if we can set it, taking into account
+      --  the setting of the Optimize_Alignment mode.
+
+      --  If Optimize_Alignment is set to Space, then packed records always
+      --  have an alignment of 1. But don't do anything for atomic records
+      --  since we may need higher alignment for indivisible access.
+
+      if Optimize_Alignment_Space (E)
+        and then Is_Record_Type (E)
+        and then Is_Packed (E)
+        and then not Is_Atomic (E)
+      then
+         Align := 1;
+
+      --  Not a record, or not packed
+
+      else
+         --  The only other cases we worry about here are where the size is
+         --  statically known at compile time.
+
          if Known_Static_Esize (E) then
             Siz := Esize (E);
 
@@ -2780,8 +2834,8 @@ package body Layout is
 
          --  Size is known, alignment is not set
 
-         --  Reset alignment to match size if size is exactly 2, 4, or 8
-         --  storage units.
+         --  Reset alignment to match size if the known size is exactly 2, 4,
+         --  or 8 storage units.
 
          if Siz = 2 * System_Storage_Unit then
             Align := 2;
@@ -2790,54 +2844,75 @@ package body Layout is
          elsif Siz = 8 * System_Storage_Unit then
             Align := 8;
 
-         --  On VMS, also reset for odd "in between" sizes, e.g. a 17-bit
-         --  record is given an alignment of 4. This is more consistent with
-         --  what DEC Ada does (-gnatd.a turns this off which can be used to
-         --  examine the value of this special transformation).
+            --  If Optimize_Alignment is set to Space, then make sure the
+            --  alignment matches the size, for example, if the size is 17
+            --  bytes then we want an alignment of 1 for the type.
 
-         elsif OpenVMS_On_Target
-           and then not Debug_Flag_Dot_A
+         elsif Optimize_Alignment_Space (E) then
+            if Siz mod (8 * System_Storage_Unit) = 0 then
+               Align := 8;
+            elsif Siz mod (4 * System_Storage_Unit) = 0 then
+               Align := 4;
+            elsif Siz mod (2 * System_Storage_Unit) = 0 then
+               Align := 2;
+            else
+               Align := 1;
+            end if;
+
+            --  If Optimize_Alignment is set to Time, then we reset for odd
+            --  "in between sizes", for example a 17 bit record is given an
+            --  alignment of 4. Note that this matches the old VMS behavior
+            --  in versions of GNAT prior to 6.1.1.
+
+         elsif Optimize_Alignment_Time (E)
            and then Siz > System_Storage_Unit
+           and then Siz <= 8 * System_Storage_Unit
          then
             if Siz <= 2 * System_Storage_Unit then
                Align := 2;
             elsif Siz <= 4 * System_Storage_Unit then
                Align := 4;
-            elsif Siz <= 8 * System_Storage_Unit then
+            else -- Siz <= 8 * System_Storage_Unit then
                Align := 8;
-            else
-               return;
             end if;
 
-         --  No special alignment fiddling needed
+            --  No special alignment fiddling needed
 
          else
             return;
          end if;
+      end if;
 
-         --  Here Align is set to the proposed improved alignment
+      --  Here we have Set Align to the proposed improved value. Make sure the
+      --  value set does not exceed Maximum_Alignment for the target.
 
-         if Align > Maximum_Alignment then
-            Align := Maximum_Alignment;
-         end if;
+      if Align > Maximum_Alignment then
+         Align := Maximum_Alignment;
+      end if;
 
-         --  Further processing for record types only to reduce the alignment
-         --  set by the above processing in some specific cases. We do not
-         --  do this for atomic records, since we need max alignment there.
+      --  Further processing for record types only to reduce the alignment
+      --  set by the above processing in some specific cases. We do not
+      --  do this for atomic records, since we need max alignment there,
 
-         if Is_Record_Type (E) then
+      if Is_Record_Type (E) and then not Is_Atomic (E) then
 
-            --  For records, there is generally no point in setting alignment
-            --  higher than word size since we cannot do better than move by
-            --  words in any case
+         --  For records, there is generally no point in setting alignment
+         --  higher than word size since we cannot do better than move by
+         --  words in any case. Omit this if we are optimizing for time,
+         --  since conceivably we may be able to do better.
 
-            if Align > System_Word_Size / System_Storage_Unit then
-               Align := System_Word_Size / System_Storage_Unit;
-            end if;
+         if Align > System_Word_Size / System_Storage_Unit
+           and then not Optimize_Alignment_Time (E)
+         then
+            Align := System_Word_Size / System_Storage_Unit;
+         end if;
 
-            --  Check components. If any component requires a higher
-            --  alignment, then we set that higher alignment in any case.
+         --  Check components. If any component requires a higher alignment,
+         --  then we set that higher alignment in any case. Don't do this if
+         --  we have Optimize_Alignment set to Space. Note that that covers
+         --  the case of packed records, where we already set alignment to 1.
 
+         if not Optimize_Alignment_Space (E) then
             declare
                Comp : Entity_Id;
 
@@ -2849,19 +2924,19 @@ package body Layout is
                         Calign : constant Uint := Alignment (Etype (Comp));
 
                      begin
-                        --  The cases to worry about are when the alignment
-                        --  of the component type is larger than the alignment
-                        --  we have so far, and either there is no component
-                        --  clause for the alignment, or the length set by
-                        --  the component clause matches the alignment set.
+                        --  The cases to process are when the alignment of the
+                        --  component type is larger than the alignment we have
+                        --  so far, and either there is no component clause for
+                        --  the component, or the length set by the component
+                        --  clause matches the length of the component type.
 
                         if Calign > Align
                           and then
                             (Unknown_Esize (Comp)
-                               or else (Known_Static_Esize (Comp)
-                                          and then
-                                        Esize (Comp) =
-                                           Calign * System_Storage_Unit))
+                              or else (Known_Static_Esize (Comp)
+                                        and then
+                                         Esize (Comp) =
+                                              Calign * System_Storage_Unit))
                         then
                            Align := UI_To_Int (Calign);
                         end if;
@@ -2872,16 +2947,17 @@ package body Layout is
                end loop;
             end;
          end if;
+      end if;
 
-         --  Set chosen alignment
+      --  Set chosen alignment, and increase Esize if necessary to match
+      --  the chosen alignment.
 
-         Set_Alignment (E, UI_From_Int (Align));
+      Set_Alignment (E, UI_From_Int (Align));
 
-         if Known_Static_Esize (E)
-           and then Esize (E) < Align * System_Storage_Unit
-         then
-            Set_Esize (E, UI_From_Int (Align * System_Storage_Unit));
-         end if;
+      if Known_Static_Esize (E)
+        and then Esize (E) < Align * System_Storage_Unit
+      then
+         Set_Esize (E, UI_From_Int (Align * System_Storage_Unit));
       end if;
    end Set_Composite_Alignment;