diff mbox

[Ada] Various fpt related clean ups

Message ID 20110802124153.GA29182@adacore.com
State New
Headers show

Commit Message

Arnaud Charlet Aug. 2, 2011, 12:41 p.m. UTC
[1] Add d.b debug option for showing available back end types

This debug option prints out information on all types that the
back end indicates it supports.

[2] Allow fpt types with more than Long_Long_Float'Digits digits

This patch takes advantage of the new infrastructure in Cstand to allow
deriving from predefined floating point types that are not in Standard and
may have more than Max_Digits digits. This will allow definition of
Interfaces.C.long_double on systems where this type is not supported by
hardware.

[3] Add support for importing predefined C floating point types

This is needed to reliably define types such as "long double"
which may have no corresponding predefined type in Ada.

The following should compile without error:

procedure it is
   type T;
   pragma Import (C, T, "long double");
begin
   null;
end it;

Tested on x86_64-pc-linux-gnu, committed on trunk

2011-08-02  Geert Bosch  <bosch@adacore.com>

	* cstand.adb (Register_Float_Type): Print information about type to
	register, if the Debug_Flag_Dot_B is set.
	* debug.adb (Debug_Flag_Dot_B): Document d.b debug option.
	* rtsfind.ads (RE_Max_Base_Digits): New run time entity.
	* sem_ch3.adb (Floating_Point_Type_Declaration): Allow declarations
	with a requested precision of more than Max_Digits digits and no more
	than Max_Base_Digits digits, if a range specification is present and the
	Predefined_Float_Types list has a suitable type to derive from.
	* sem_ch3.adb (Rep_Item_Too_Early): Avoid generating error in the
	case of type completion with pragma Import
	* sem_prag.adb
	(Process_Import_Predefined_Type): Processing to complete a type
	with pragma Import. Currently supports floating point types only.
	(Set_Convention_From_Pragma): Do nothing without underlying type.
	(Process_Convention): Guard against absence of underlying type,
	which may happen when importing incomplete types.
	(Process_Import_Or_Interface): Handle case of importing predefined
	types. Tweak error message.
diff mbox

Patch

Index: cstand.adb
===================================================================
--- cstand.adb	(revision 177137)
+++ cstand.adb	(working copy)
@@ -467,7 +467,7 @@ 
             N   : Node_Id := First (Back_End_Float_Types);
 
          begin
-            if Digits_Value (LLF) > Max_HW_Digs then
+            if Present (LLF) and then Digits_Value (LLF) > Max_HW_Digs then
                LLF := Empty;
             end if;
 
@@ -2008,16 +2008,78 @@ 
       Size      : Positive;
       Alignment : Natural)
    is
-      Last : Natural := Name'First - 1;
+      T    : String (1 .. Name'Length);
+      Last : Natural := 0;
 
+      procedure Dump;
+      --  Dump information given by the back end for the type to register
+
+      procedure Dump is
+      begin
+         Write_Str ("type " & T (1 .. Last) & " is ");
+
+         if Count > 0 then
+            Write_Str ("array (1 .. ");
+            Write_Int (Int (Count));
+
+            if Complex then
+               Write_Str (", 1 .. 2");
+            end if;
+
+            Write_Str (") of ");
+
+         elsif Complex then
+            Write_Str ("array (1 .. 2) of ");
+         end if;
+
+         if Digs > 0 then
+            Write_Str ("digits ");
+            Write_Int (Int (Digs));
+            Write_Line (";");
+
+            Write_Str ("pragma Float_Representation (");
+
+            case Float_Rep is
+               when IEEE_Binary =>  Write_Str ("IEEE");
+               when VAX_Native =>
+                  case Digs is
+                     when  6 =>     Write_Str ("VAXF");
+                     when  9 =>     Write_Str ("VAXD");
+                     when 15 =>     Write_Str ("VAXG");
+                     when others => Write_Str ("VAX_"); Write_Int (Int (Digs));
+                  end case;
+               when AAMP =>         Write_Str ("AAMP");
+            end case;
+            Write_Line (", " & T & ");");
+
+         else
+            Write_Str ("mod 2**");
+            Write_Int (Int (Size / Positive'Max (1, Count)));
+            Write_Line (";");
+         end if;
+
+         Write_Str ("for " & T & "'Size use ");
+         Write_Int (Int (Size));
+         Write_Line (";");
+
+         Write_Str ("for " & T & "'Alignment use ");
+         Write_Int (Int (Alignment / 8));
+         Write_Line (";");
+      end Dump;
+
    begin
-      for J in Name'Range loop
-         if Name (J) = ASCII.NUL then
+      for J in T'Range loop
+         T (J) := Name (Name'First + J - 1);
+         if T (J) = ASCII.NUL then
             Last := J - 1;
             exit;
          end if;
       end loop;
 
+      if Debug_Flag_Dot_B then
+         Dump;
+      end if;
+
       if Digs > 0 and then not Complex and then Count = 0 then
          declare
             Ent   : constant Entity_Id := New_Standard_Entity;
@@ -2026,7 +2088,7 @@ 
          begin
             Set_Defining_Identifier
               (New_Node (N_Full_Type_Declaration, Stloc), Ent);
-            Make_Name (Ent, String (Name (Name'First .. Last)));
+            Make_Name (Ent, T (1 .. Last));
             Set_Scope (Ent, Standard_Standard);
             Build_Float_Type (Ent, Esize, Float_Rep, Pos (Digs));
             Set_RM_Size (Ent, UI_From_Int (Int (Size)));
Index: debug.adb
===================================================================
--- debug.adb	(revision 177040)
+++ debug.adb	(working copy)
@@ -92,7 +92,7 @@ 
    --  dZ   Generate listing showing the contents of the dispatch tables
 
    --  d.a  Force Target_Strict_Alignment mode to True
-   --  d.b
+   --  d.b  Dump backend types
    --  d.c  Generate inline concatenation, do not call procedure
    --  d.d
    --  d.e
@@ -500,6 +500,9 @@ 
    --       would normally be false. Can be used for testing strict alignment
    --       circuitry in the compiler.
 
+   --  d.b  Dump back end types. During Create_Standard, the back end is
+   --       queried for all available types. This option shows them.
+
    --  d.c  Generate inline concatenation, instead of calling one of the
    --       System.Concat_n.Str_Concat_n routines in cases where the latter
    --       routines would normally be called.
Index: rtsfind.ads
===================================================================
--- rtsfind.ads	(revision 176998)
+++ rtsfind.ads	(working copy)
@@ -650,6 +650,7 @@ 
      RE_Interrupt_Priority,              -- System
      RE_Lib_Stop,                        -- System
      RE_Low_Order_First,                 -- System
+     RE_Max_Base_Digits,                 -- System
      RE_Max_Priority,                    -- System
      RE_Null_Address,                    -- System
      RE_Priority,                        -- System
@@ -1827,6 +1828,7 @@ 
      RE_Interrupt_Priority               => System,
      RE_Lib_Stop                         => System,
      RE_Low_Order_First                  => System,
+     RE_Max_Base_Digits                  => System,
      RE_Max_Priority                     => System,
      RE_Null_Address                     => System,
      RE_Priority                         => System,
Index: sem_ch13.adb
===================================================================
--- sem_ch13.adb	(revision 177123)
+++ sem_ch13.adb	(working copy)
@@ -6958,6 +6958,7 @@ 
 
       if Is_Incomplete_Or_Private_Type (T)
         and then No (Underlying_Type (T))
+        and then Get_Pragma_Id (N) /= Pragma_Import
       then
          Error_Msg_N
            ("representation item must be after full type declaration", N);
Index: sem_ch3.adb
===================================================================
--- sem_ch3.adb	(revision 177135)
+++ sem_ch3.adb	(working copy)
@@ -15034,13 +15034,15 @@ 
 
    procedure Floating_Point_Type_Declaration (T : Entity_Id; Def : Node_Id) is
       Digs          : constant Node_Id := Digits_Expression (Def);
+      Max_Digs_Val  : constant Uint := Digits_Value (Standard_Long_Long_Float);
       Digs_Val      : Uint;
       Base_Typ      : Entity_Id;
       Implicit_Base : Entity_Id;
       Bound         : Node_Id;
 
       function Can_Derive_From (E : Entity_Id) return Boolean;
-      --  Find if given digits value allows derivation from specified type
+      --  Find if given digits value, and possibly a specified range, allows
+      --  derivation from specified type
 
       ---------------------
       -- Can_Derive_From --
@@ -15091,25 +15093,48 @@ 
 
       Process_Real_Range_Specification (Def);
 
-      if Can_Derive_From (Standard_Short_Float) then
-         Base_Typ := Standard_Short_Float;
-      elsif Can_Derive_From (Standard_Float) then
-         Base_Typ := Standard_Float;
-      elsif Can_Derive_From (Standard_Long_Float) then
-         Base_Typ := Standard_Long_Float;
-      elsif Can_Derive_From (Standard_Long_Long_Float) then
-         Base_Typ := Standard_Long_Long_Float;
+      --  Check that requested number of digits is not too high.
 
-      --  If we can't derive from any existing type, use long_long_float
+      if Digs_Val > Max_Digs_Val then
+         --  The check for Max_Base_Digits may be somewhat expensive, as it
+         --  requires reading System, so only do it when necessary.
+
+         declare
+            Max_Base_Digits : constant Uint :=
+               Expr_Value (Expression (Parent (RTE (RE_Max_Base_Digits))));
+         begin
+            if Digs_Val > Max_Base_Digits then
+               Error_Msg_Uint_1 := Max_Base_Digits;
+               Error_Msg_N ("digits value out of range, maximum is ^", Digs);
+
+            elsif No (Real_Range_Specification (Def)) then
+               Error_Msg_Uint_1 := Max_Digs_Val;
+               Error_Msg_N ("types with more than ^ digits need range spec "
+                 & "('R'M 3.5.7(6))", Digs);
+            end if;
+         end;
+      end if;
+
+      Base_Typ := First (Predefined_Float_Types);
+
+      while Present (Base_Typ) and then not Can_Derive_From (Base_Typ) loop
+         Next (Base_Typ);
+      end loop;
+
+      --  If we can't derive from any existing type, use Long_Long_Float
       --  and give appropriate message explaining the problem.
 
-      else
+      if No (Base_Typ) then
          Base_Typ := Standard_Long_Long_Float;
 
-         if Digs_Val >= Digits_Value (Standard_Long_Long_Float) then
-            Error_Msg_Uint_1 := Digits_Value (Standard_Long_Long_Float);
-            Error_Msg_N ("digits value out of range, maximum is ^", Digs);
+         if Digs_Val > Max_Digs_Val then
+            --  It might be the case that there is a type with the requested
+            --  range, just not the combination of digits and range.
 
+            Error_Msg_N
+              ("no predefined type has requested range and precision",
+               Real_Range_Specification (Def));
+
          else
             Error_Msg_N
               ("range too large for any predefined type",
Index: sem_prag.adb
===================================================================
--- sem_prag.adb	(revision 177123)
+++ sem_prag.adb	(working copy)
@@ -659,6 +659,11 @@ 
       procedure Process_Import_Or_Interface;
       --  Common processing for Import of Interface
 
+      procedure Process_Import_Predefined_Type;
+      --  Processing for completing a type with pragma Import. This is used
+      --  to declare types that match predefined C types, especially for cases
+      --  without corresponding Ada predefined type.
+
       procedure Process_Inline (Active : Boolean);
       --  Common processing for Inline and Inline_Always. The parameter
       --  indicates if the inline pragma is active, i.e. if it should actually
@@ -2875,7 +2880,9 @@ 
             Set_Convention (E, C);
             Set_Has_Convention_Pragma (E);
 
-            if Is_Incomplete_Or_Private_Type (E) then
+            if Is_Incomplete_Or_Private_Type (E)
+              and then Present (Underlying_Type (E))
+            then
                Set_Convention            (Underlying_Type (E), C);
                Set_Has_Convention_Pragma (Underlying_Type (E), True);
             end if;
@@ -3033,7 +3040,8 @@ 
            or else Rep_Item_Too_Early (E, N)
          then
             raise Pragma_Exit;
-         else
+
+         elsif Present (Underlying_Type (E)) then
             E := Underlying_Type (E);
          end if;
 
@@ -3850,6 +3858,58 @@ 
          end loop;
       end Process_Generic_List;
 
+      ------------------------------------
+      -- Process_Import_Predefined_Type --
+      ------------------------------------
+
+      procedure Process_Import_Predefined_Type is
+         Loc  : constant Source_Ptr := Sloc (N);
+         Ftyp : Node_Id := First (Predefined_Float_Types);
+         Decl : Node_Id;
+         Def  : Node_Id;
+         Nam  : Name_Id;
+      begin
+         String_To_Name_Buffer (Strval (Expression (Arg3)));
+         Nam := Name_Find;
+
+         while Present (Ftyp) and then Chars (Ftyp) /= Nam loop
+            Next (Ftyp);
+         end loop;
+
+         if Present (Ftyp) then
+            --  Don't build a derived type declaration, because predefined C
+            --  types have no declaration anywhere, so cannot really be named.
+            --  Instead build a full type declaration, starting with an
+            --  appropriate type definition is built
+
+            if Is_Floating_Point_Type (Ftyp) then
+               Def := Make_Floating_Point_Definition (Loc,
+                 Make_Integer_Literal (Loc, Digits_Value (Ftyp)),
+                 Make_Real_Range_Specification (Loc,
+                   Make_Real_Literal (Loc, Realval (Type_Low_Bound (Ftyp))),
+                   Make_Real_Literal (Loc, Realval (Type_High_Bound (Ftyp)))));
+
+            else
+               --  Should never have a predefined type we cannot handle
+               raise Program_Error;
+            end if;
+
+            --  Build and insert a Full_Type_Declaration, which will be
+            --  analyzed as soon as this list entry has been analyzed.
+
+            Decl := Make_Full_Type_Declaration (Loc,
+              Make_Defining_Identifier (Loc, Chars (Expression (Arg2))),
+              Type_Definition => Def);
+
+            Insert_After (N, Decl);
+            Mark_Rewrite_Insertion (Decl);
+
+         else
+            Error_Pragma_Arg ("no matching type found for pragma%",
+            Arg2);
+         end if;
+      end Process_Import_Predefined_Type;
+
       ---------------------------------
       -- Process_Import_Or_Interface --
       ---------------------------------
@@ -4118,9 +4178,17 @@ 
                end if;
             end;
 
+         elsif Nkind (Parent (Def_Id)) = N_Incomplete_Type_Declaration then
+            Check_No_Link_Name;
+            Check_Arg_Count (3);
+            Check_Arg_Is_Static_Expression (Arg3, Standard_String);
+
+            Process_Import_Predefined_Type;
+
          else
             Error_Pragma_Arg
-              ("second argument of pragma% must be object or subprogram",
+              ("second argument of pragma% must be object, subprogram" &
+               " or incomplete type",
                Arg2);
          end if;