From c63bb4f3aaa18b5e4c8722c655187d592faecde3 Mon Sep 17 00:00:00 2001
From: Eric Botcazou <ebotcazou@adacore.com>
Date: Mon, 21 Dec 2020 08:37:34 +0100
Subject: [PATCH] [Ada] Preliminary cleanup in floating-point output
 implementation

gcc/ada/

	* exp_intr.adb: Remove with/use clauses for Urealp.
	(Expand_Is_Negative): Delete.
	(Expand_Intrinsic_Call): Do not call it.
	* rtsfind.ads (RE_Id): Remove RE_Float_Unsigned.
	(RE_Unit_Table): Remove entry for RE_Float_Unsigned.
	* snames.ads-tmpl (Name_Is_Negative): Delete.
	* libgnat/s-imgrea.ads (Set_Image_Real): Fix mode of S parameter.
	* libgnat/s-imgrea.adb: Add with/use clauses for System.Img_Util.
	(LLU): New subtype.
	(Maxdigs): Use it.
	(Is_Negative): Reimplement.
	(Image_Floating_Point): Simplify.
	(Set_Image_Real): Fix mode of S parameter.  Remove the low-level
	processing on characters.  Flip the sign of the Scale variable.
	Compute the maximum number of digits for the straight notation.
	Call Set_Decimal_Digits at the end to do the final formatting.
	* libgnat/s-imguti.ads (Floating_Invalid_Value): New type.
	(Set_Floating_Invalid_Value): New procedure.
	* libgnat/s-imguti.adb (Set_Floating_Invalid_Value): Implement it
	based on existing code from Set_Image_Real.
	* libgnat/s-unstyp.ads (Float_Unsigned): Delete.
---
 gcc/ada/exp_intr.adb         |  59 -----
 gcc/ada/libgnat/s-imgrea.adb | 469 ++++++++---------------------------
 gcc/ada/libgnat/s-imgrea.ads |   2 +-
 gcc/ada/libgnat/s-imguti.adb |  81 ++++++
 gcc/ada/libgnat/s-imguti.ads |  15 ++
 gcc/ada/libgnat/s-unstyp.ads |   3 -
 gcc/ada/rtsfind.ads          |   2 -
 gcc/ada/snames.ads-tmpl      |   1 -
 8 files changed, 196 insertions(+), 436 deletions(-)

diff --git a/gcc/ada/exp_intr.adb b/gcc/ada/exp_intr.adb
index 0eecd1ca53cd..e2c3e3432784 100644
--- a/gcc/ada/exp_intr.adb
+++ b/gcc/ada/exp_intr.adb
@@ -54,7 +54,6 @@ with Snames;   use Snames;
 with Stand;    use Stand;
 with Tbuild;   use Tbuild;
 with Uintp;    use Uintp;
-with Urealp;   use Urealp;
 
 package body Exp_Intr is
 
@@ -66,9 +65,6 @@ package body Exp_Intr is
    --  Expand a call to an intrinsic arithmetic operator when the operand
    --  types or sizes are not identical.
 
-   procedure Expand_Is_Negative (N : Node_Id);
-   --  Expand a call to the intrinsic Is_Negative function
-
    procedure Expand_Dispatching_Constructor_Call (N : Node_Id);
    --  Expand a call to an instantiation of Generic_Dispatching_Constructor
    --  into a dispatching call to the actual subprogram associated with the
@@ -636,9 +632,6 @@ package body Exp_Intr is
       then
          Expand_Import_Call (N);
 
-      elsif Nam = Name_Is_Negative then
-         Expand_Is_Negative (N);
-
       elsif Nam = Name_Rotate_Left then
          Expand_Shift (N, E, N_Op_Rotate_Left);
 
@@ -696,58 +689,6 @@ package body Exp_Intr is
       end if;
    end Expand_Intrinsic_Call;
 
-   ------------------------
-   -- Expand_Is_Negative --
-   ------------------------
-
-   procedure Expand_Is_Negative (N : Node_Id) is
-      Loc   : constant Source_Ptr := Sloc (N);
-      Opnd  : constant Node_Id    := Relocate_Node (First_Actual (N));
-
-   begin
-
-      --  We replace the function call by the following expression
-
-      --    if Opnd < 0.0 then
-      --       True
-      --    else
-      --       if Opnd > 0.0 then
-      --          False;
-      --       else
-      --          Float_Unsigned!(Float (Opnd)) /= 0
-      --       end if;
-      --    end if;
-
-      Rewrite (N,
-        Make_If_Expression (Loc,
-          Expressions => New_List (
-            Make_Op_Lt (Loc,
-              Left_Opnd  => Duplicate_Subexpr (Opnd),
-              Right_Opnd => Make_Real_Literal (Loc, Ureal_0)),
-
-            New_Occurrence_Of (Standard_True, Loc),
-
-            Make_If_Expression (Loc,
-             Expressions => New_List (
-               Make_Op_Gt (Loc,
-                 Left_Opnd  => Duplicate_Subexpr_No_Checks (Opnd),
-                 Right_Opnd => Make_Real_Literal (Loc, Ureal_0)),
-
-               New_Occurrence_Of (Standard_False, Loc),
-
-                Make_Op_Ne (Loc,
-                  Left_Opnd =>
-                    Unchecked_Convert_To
-                      (RTE (RE_Float_Unsigned),
-                       Convert_To
-                         (Standard_Float,
-                          Duplicate_Subexpr_No_Checks (Opnd))),
-                  Right_Opnd =>
-                    Make_Integer_Literal (Loc, 0)))))));
-
-      Analyze_And_Resolve (N, Standard_Boolean);
-   end Expand_Is_Negative;
-
    ------------------
    -- Expand_Shift --
    ------------------
diff --git a/gcc/ada/libgnat/s-imgrea.adb b/gcc/ada/libgnat/s-imgrea.adb
index 6c08dcff0526..3ec41561b12b 100644
--- a/gcc/ada/libgnat/s-imgrea.adb
+++ b/gcc/ada/libgnat/s-imgrea.adb
@@ -31,11 +31,15 @@
 
 with System.Img_LLU;    use System.Img_LLU;
 with System.Img_Uns;    use System.Img_Uns;
+with System.Img_Util;   use System.Img_Util;
 with System.Powten_LLF; use System.Powten_LLF;
+
 with System.Float_Control;
 
 package body System.Img_Real is
 
+   subtype LLU is Long_Long_Unsigned;
+
    --  The following defines the maximum number of digits that we can convert
    --  accurately. This is limited by the precision of Long_Long_Float, and
    --  also by the number of digits we can hold in Long_Long_Unsigned, which
@@ -46,18 +50,13 @@ package body System.Img_Real is
    --  implementations, and at worst, the only loss is for some precision
    --  in very high precision floating-point output.
 
-   --  Note that in the following, the "-2" accounts for the sign and one
+   --  Note that in the following, the "-2" accounts for the space and one
    --  extra digit, since we need the maximum number of 9's that can be
    --  represented, e.g. for the 64-bit case, Long_Long_Unsigned'Width is
    --  21, since the maximum value (approx 1.8E+19) has 20 digits, but the
    --  maximum number of 9's that can be represented is only 19.
 
-   Maxdigs : constant :=
-               Natural'Min
-                 (Long_Long_Unsigned'Width - 2, Long_Long_Float'Digits);
-
-   Unsdigs : constant := Unsigned'Width - 2;
-   --  Number of digits that can be converted using type Unsigned
+   Maxdigs : constant := Natural'Min (LLU'Width - 2, Long_Long_Float'Digits);
 
    Maxscaling : constant := 5000;
    --  Max decimal scaling required during conversion of floating-point
@@ -69,7 +68,8 @@ package body System.Img_Real is
    --  enough room for scaling such values
 
    function Is_Negative (V : Long_Long_Float) return Boolean;
-   pragma Import (Intrinsic, Is_Negative);
+   --  Return True if V is negative for the purpose of the output, i.e. return
+   --  True for negative zeros only if Signed_Zeros is True.
 
    --------------------------
    -- Image_Floating_Point --
@@ -86,14 +86,12 @@ package body System.Img_Real is
    begin
       --  Decide whether a blank should be prepended before the call to
       --  Set_Image_Real. We generate a blank for positive values, and
-      --  also for positive zeroes. For negative zeroes, we generate a
+      --  also for positive zeros. For negative zeros, we generate a
       --  blank only if Signed_Zeros is False (the RM only permits the
       --  output of -0.0 when Signed_Zeros is True). We do not generate
       --  a blank for positive infinity, since we output an explicit +.
 
-      if (not Is_Negative (V) and then V <= Long_Long_Float'Last)
-        or else (not Long_Long_Float'Signed_Zeros and then V = -0.0)
-      then
+      if not Is_Negative (V) and then V <= Long_Long_Float'Last then
          pragma Annotate (CodePeer, False_Positive, "condition predetermined",
                           "CodePeer analysis ignores NaN and Inf values");
          pragma Assert (S'Last > 1);
@@ -133,68 +131,59 @@ package body System.Img_Real is
       Set_Image_Real (V, S, P, 1, Aft, 0);
    end Image_Ordinary_Fixed_Point;
 
+   -----------------
+   -- Is_Negative --
+   -----------------
+
+   function Is_Negative (V : Long_Long_Float) return Boolean is
+   begin
+      if V < 0.0 then
+         return True;
+
+      elsif V > 0.0 then
+         return False;
+
+      elsif not Long_Long_Float'Signed_Zeros then
+         return False;
+
+      else
+         return Long_Long_Float'Copy_Sign (1.0, V) < 0.0;
+      end if;
+   end Is_Negative;
+
    --------------------
    -- Set_Image_Real --
    --------------------
 
    procedure Set_Image_Real
      (V    : Long_Long_Float;
-      S    : out String;
+      S    : in out String;
       P    : in out Natural;
       Fore : Natural;
       Aft  : Natural;
       Exp  : Natural)
    is
       NFrac : constant Natural := Natural'Max (Aft, 1);
-      Minus : Boolean;
-      X     : Long_Long_Float;
-      Scale : Integer;
-      Expon : Integer;
+      --  Number of digits after the decimal point
 
-      Digs : String (1 .. Max_Real_Image_Length);
-      --  Array used to hold digits of converted integer value. This is a large
-      --  enough buffer to accommodate ludicrous Fore/Aft/Exp combinations.
+      Digs : String (1 .. 3 + Maxdigs);
+      --  Array used to hold digits of converted integer value
 
       Ndigs : Natural;
       --  Number of digits stored in Digs (and also subscript of last digit)
 
+      Scale : Integer := 0;
+      --  Exponent such that the result is Digs (1 .. NDigs) * 10**(-Scale)
+
+      X : Long_Long_Float;
+      --  Current absolute value of the input after scaling
+
       procedure Adjust_Scale (S : Natural);
       --  Adjusts the value in X by multiplying or dividing by a power of
-      --  ten so that it is in the range 10**(S-1) <= X < 10**S. Includes
-      --  adding 0.5 to round the result, readjusting if the rounding causes
-      --  the result to wander out of the range. Scale is adjusted to reflect
-      --  the power of ten used to divide the result (i.e. one is added to
-      --  the scale value for each division by 10.0, or one is subtracted
-      --  for each multiplication by 10.0).
-
-      procedure Convert_Integer;
-      --  Takes the value in X, outputs integer digits into Digs. On return,
-      --  Ndigs is set to the number of digits stored. The digits are stored
-      --  in Digs (1 .. Ndigs),
-
-      procedure Set (C : Character);
-      --  Sets character C in output buffer
-
-      procedure Set_Blanks_And_Sign (N : Integer);
-      --  Sets leading blanks and minus sign if needed. N is the number of
-      --  positions to be filled (a minus sign is output even if N is zero
-      --  or negative, but for a positive value, if N is non-positive, then
-      --  the call has no effect).
-
-      procedure Set_Digs (S, E : Natural);
-      --  Set digits S through E from Digs buffer. No effect if S > E
-
-      procedure Set_Special_Fill (N : Natural);
-      --  After outputting +Inf, -Inf or NaN, this routine fills out the
-      --  rest of the field with * characters. The argument is the number
-      --  of characters output so far (either 3 or 4)
-
-      procedure Set_Zeros (N : Integer);
-      --  Set N zeros, no effect if N is negative
-
-      pragma Inline (Set);
-      pragma Inline (Set_Digs);
-      pragma Inline (Set_Zeros);
+      --  ten so that it is in the range 10**(S-1) <= X < 10**S. Scale is
+      --  adjusted to reflect the power of ten used to divide the result,
+      --  i.e. one is added to the scale value for each multiplication by
+      --  10.0 and one is subtracted for each division by 10.0.
 
       ------------------
       -- Adjust_Scale --
@@ -216,9 +205,9 @@ package body System.Img_Real is
 
             loop
                XP := X * Powten (Maxpow);
-               exit when XP >= Powten (S - 1) or else Scale < -Maxscaling;
+               exit when XP >= Powten (S - 1) or else Scale > Maxscaling;
                X := XP;
-               Scale := Scale - Maxpow;
+               Scale := Scale + Maxpow;
             end loop;
 
             --  The following exception is only raised in case of erroneous
@@ -227,7 +216,7 @@ package body System.Img_Real is
             --  when a system which is supposed to be IEEE-compliant, but
             --  has been reconfigured to flush denormals to zero.
 
-            if Scale < -Maxscaling then
+            if Scale > Maxscaling then
                raise Constraint_Error;
             end if;
 
@@ -275,7 +264,7 @@ package body System.Img_Real is
             end loop;
 
             X := XP;
-            Scale := Scale - Mid;
+            Scale := Scale + Mid;
 
          --  Cases where scaling down is required
 
@@ -288,9 +277,9 @@ package body System.Img_Real is
 
             loop
                XP := X / Powten (Maxpow);
-               exit when XP < Powten (S) or else Scale > Maxscaling;
+               exit when XP < Powten (S) or else Scale < -Maxscaling;
                X := XP;
-               Scale := Scale + Maxpow;
+               Scale := Scale - Maxpow;
             end loop;
 
             --  The following exception is only raised in case of erroneous
@@ -299,7 +288,7 @@ package body System.Img_Real is
             --  when a system which is supposed to be IEEE-compliant, but
             --  has been reconfigured to flush denormals to zero.
 
-            if Scale > Maxscaling then
+            if Scale < -Maxscaling then
                raise Constraint_Error;
             end if;
 
@@ -341,141 +330,15 @@ package body System.Img_Real is
             end loop;
 
             X := XP;
-            Scale := Scale + Mid;
+            Scale := Scale - Mid;
 
          --  Here we are already scaled right
 
          else
             null;
          end if;
-
-         --  Round, readjusting scale if needed. Note that if a readjustment
-         --  occurs, then it is never necessary to round again, because there
-         --  is no possibility of such a second rounding causing a change.
-
-         X := X + 0.5;
-
-         if X >= Powten (S) then
-            X := X / 10.0;
-            Scale := Scale + 1;
-         end if;
-
       end Adjust_Scale;
 
-      ---------------------
-      -- Convert_Integer --
-      ---------------------
-
-      procedure Convert_Integer is
-      begin
-         --  Use Unsigned routine if possible, since on many machines it will
-         --  be significantly more efficient than the Long_Long_Unsigned one.
-
-         if X < Powten (Unsdigs) then
-            pragma Assert (X in 0.0 .. Long_Long_Float (Unsigned'Last));
-            Ndigs := 0;
-            Set_Image_Unsigned
-              (Unsigned (Long_Long_Float'Truncation (X)),
-               Digs, Ndigs);
-
-         --  But if we want more digits than fit in Unsigned, we have to use
-         --  the Long_Long_Unsigned routine after all.
-
-         else
-            pragma Assert (X < Powten (Maxdigs));
-            pragma Assert
-              (X in 0.0 .. Long_Long_Float (Long_Long_Unsigned'Last));
-
-            Ndigs := 0;
-            Set_Image_Long_Long_Unsigned
-              (Long_Long_Unsigned (Long_Long_Float'Truncation (X)),
-               Digs, Ndigs);
-         end if;
-      end Convert_Integer;
-
-      ---------
-      -- Set --
-      ---------
-
-      procedure Set (C : Character) is
-      begin
-         pragma Assert (P in S'First - 1 .. S'Last - 1);
-         --  No check is done as documented in the header: updating P to point
-         --  to the last character stored, the caller promises that the buffer
-         --  is large enough and no check is made for this. Constraint_Error
-         --  will not necessarily be raised if this requirement is violated,
-         --  since it is perfectly valid to compile this unit with checks off.
-         P := P + 1;
-         S (P) := C;
-      end Set;
-
-      -------------------------
-      -- Set_Blanks_And_Sign --
-      -------------------------
-
-      procedure Set_Blanks_And_Sign (N : Integer) is
-      begin
-         if Minus then
-            for J in 1 .. N - 1 loop
-               Set (' ');
-            end loop;
-
-            Set ('-');
-
-         else
-            for J in 1 .. N loop
-               Set (' ');
-            end loop;
-         end if;
-      end Set_Blanks_And_Sign;
-
-      --------------
-      -- Set_Digs --
-      --------------
-
-      procedure Set_Digs (S, E : Natural) is
-      begin
-         pragma Assert (S >= Digs'First and E <= Digs'Last);
-         --  S and E should be in the Digs array range
-         for J in S .. E loop
-            Set (Digs (J));
-         end loop;
-      end Set_Digs;
-
-      ----------------------
-      -- Set_Special_Fill --
-      ----------------------
-
-      procedure Set_Special_Fill (N : Natural) is
-         F : Natural;
-
-      begin
-         pragma Assert ((Fore + Aft - N + 1) in Natural);
-         --  Fore + Aft - N + 1 should be in the Natural range
-         F := Fore + 1 + Aft - N;
-
-         if Exp /= 0 then
-            pragma Assert (F + Exp + 1 <= Natural'Last);
-            --  F + Exp + 1 should be in the Natural range
-            F := F + Exp + 1;
-         end if;
-
-         for J in 1 .. F loop
-            Set ('*');
-         end loop;
-      end Set_Special_Fill;
-
-      ---------------
-      -- Set_Zeros --
-      ---------------
-
-      procedure Set_Zeros (N : Integer) is
-      begin
-         for J in 1 .. N loop
-            Set ('0');
-         end loop;
-      end Set_Zeros;
-
    --  Start of processing for Set_Image_Real
 
    begin
@@ -486,9 +349,7 @@ package body System.Img_Real is
 
       System.Float_Control.Reset;
 
-      Scale := 0;
-
-      --  Deal with invalid values first,
+      --  Deal with invalid values first
 
       if not V'Valid then
 
@@ -500,218 +361,86 @@ package body System.Img_Real is
          --  converting to infinity or some other value, or causing an
          --  exception to be raised is fine.
 
-         --  If the following test succeeds, then we definitely have
-         --  an infinite value, so we print Inf.
+         --  If the following two tests succeed, then we definitely have
+         --  an infinite value, so we print +Inf or -Inf.
 
          if V > Long_Long_Float'Last then
             pragma Annotate (CodePeer, False_Positive, "dead code",
                              "CodePeer analysis ignores NaN and Inf values");
             pragma Annotate (CodePeer, False_Positive, "test always true",
                              "CodePeer analysis ignores NaN and Inf values");
-            Set ('+');
-            Set ('I');
-            Set ('n');
-            Set ('f');
-            Set_Special_Fill (4);
-         --  In all other cases we print NaN
 
-         elsif V < Long_Long_Float'First then
-            Set ('-');
-            Set ('I');
-            Set ('n');
-            Set ('f');
-            Set_Special_Fill (4);
-         else
-            Set ('N');
-            Set ('a');
-            Set ('N');
-            Set_Special_Fill (3);
-         end if;
+            Set_Floating_Invalid_Value (Infinity, S, P, Fore, Aft, Exp);
 
-         return;
-      end if;
-
-      --  Positive values
-
-      if V > 0.0 then
-         X := V;
-         Minus := False;
-
-      --  Negative values
-
-      elsif V < 0.0 then
-         X := -V;
-         Minus := True;
+         elsif V < Long_Long_Float'First then
+            Set_Floating_Invalid_Value (Minus_Infinity, S, P, Fore, Aft, Exp);
 
-      --  Zero values
+         --  In all other cases we print NaN
 
-      elsif V = 0.0 then
-         if Long_Long_Float'Signed_Zeros and then Is_Negative (V) then
-            Minus := True;
          else
-            Minus := False;
-         end if;
-
-         Set_Blanks_And_Sign (Fore - 1);
-         Set ('0');
-         Set ('.');
-         Set_Zeros (NFrac);
-
-         if Exp /= 0 then
-            Set ('E');
-            Set ('+');
-            Set_Zeros (Natural'Max (1, Exp - 1));
+            Set_Floating_Invalid_Value (Not_A_Number, S, P, Fore, Aft, Exp);
          end if;
 
          return;
-
-      else
-         --  It should not be possible for a NaN to end up here.
-         --  Either the 'Valid test has failed, or we have some form
-         --  of erroneous execution. Raise Constraint_Error instead of
-         --  attempting to go ahead printing the value.
-
-         raise Constraint_Error;
       end if;
 
-      --  X and Minus are set here, and X is known to be a valid,
-      --  non-zero floating-point number.
-
-      --  Case of non-zero value with Exp = 0
-
-      if Exp = 0 then
-
-         --  First step is to multiply by 10 ** Nfrac to get an integer
-         --  value to be output, an then add 0.5 to round the result.
-
-         declare
-            NF : Natural := NFrac;
-
-         begin
-            loop
-               --  If we are larger than Powten (Maxdigs) now, then
-               --  we have too many significant digits, and we have
-               --  not even finished multiplying by NFrac (NF shows
-               --  the number of unaccounted-for digits).
-
-               if X >= Powten (Maxdigs) then
+      --  Set the first character like Image
 
-                  --  In this situation, we only to generate a reasonable
-                  --  number of significant digits, and then zeroes after.
-                  --  So first we rescale to get:
+      Digs (1) := (if Is_Negative (V) then '-' else ' ');
+      Ndigs := 1;
 
-                  --    10 ** (Maxdigs - 1) <= X < 10 ** Maxdigs
+      X := abs (V);
 
-                  --  and then convert the resulting integer
+      --  If X is zero, we are done
 
-                  Adjust_Scale (Maxdigs);
-                  Convert_Integer;
+      if X = 0.0 then
+         Digs (2) := '0';
+         Ndigs := 2;
 
-                  --  If that caused rescaling, then add zeros to the end
-                  --  of the number to account for this scaling. Also add
-                  --  zeroes to account for the undone multiplications
-
-                  for J in 1 .. Scale + NF loop
-                     Ndigs := Ndigs + 1;
-                     pragma Assert (Ndigs <= Digs'Last);
-                     Digs (Ndigs) := '0';
-                  end loop;
-
-                  exit;
-
-               --  If multiplication is complete, then convert the resulting
-               --  integer after rounding (note that X is non-negative)
-
-               elsif NF = 0 then
-                  X := X + 0.5;
-                  Convert_Integer;
-                  exit;
-
-               --  Otherwise we can go ahead with the multiplication. If it
-               --  can be done in one step, then do it in one step.
-
-               elsif NF < Maxpow then
-                  X := X * Powten (NF);
-                  NF := 0;
-
-               --  If it cannot be done in one step, then do partial scaling
-
-               else
-                  X := X * Powten (Maxpow);
-                  NF := NF - Maxpow;
-               end if;
-            end loop;
-         end;
-
-         --  If number of available digits is less or equal to NFrac,
-         --  then we need an extra zero before the decimal point.
-
-         if Ndigs <= NFrac then
-            Set_Blanks_And_Sign (Fore - 1);
-            Set ('0');
-            Set ('.');
-            Set_Zeros (NFrac - Ndigs);
-            Set_Digs (1, Ndigs);
-
-         --  Normal case with some digits before the decimal point
-
-         else
-            Set_Blanks_And_Sign (Fore - (Ndigs - NFrac));
-            Set_Digs (1, Ndigs - NFrac);
-            Set ('.');
-            Set_Digs (Ndigs - NFrac + 1, Ndigs);
-         end if;
-
-      --  Case of non-zero value with non-zero Exp value
+      --  Otherwise, scale X and convert it to an integer
 
       else
-         --  If NFrac is less than Maxdigs, then all the fraction digits are
-         --  significant, so we can scale the resulting integer accordingly.
+         --  In exponent notation, we need exactly NFrac + 1 digits and always
+         --  round the last one.
 
-         if NFrac < Maxdigs then
-            Adjust_Scale (NFrac + 1);
-            Convert_Integer;
+         if Exp > 0 then
+            Adjust_Scale (Natural'Min (NFrac + 1, Maxdigs));
+            X := X + 0.5;
 
-         --  Otherwise, we get the maximum number of digits available
+         --  In straight notation, we compute the maximum number of digits and
+         --  compare how many of them will be put after the decimal point with
+         --  Nfrac, in order to find out whether we need to round the last one
+         --  here or whether the rounding is performed by Set_Decimal_Digits.
 
          else
             Adjust_Scale (Maxdigs);
-            Convert_Integer;
-
-            for J in 1 .. NFrac - Maxdigs + 1 loop
-               Ndigs := Ndigs + 1;
-               pragma Assert (Ndigs <= Digs'Last);
-               Digs (Ndigs) := '0';
-               Scale := Scale - 1;
-            end loop;
+            if Scale <= NFrac then
+               X := X + 0.5;
+            end if;
          end if;
 
-         Set_Blanks_And_Sign (Fore - 1);
-         Set (Digs (1));
-         Set ('.');
-         Set_Digs (2, Ndigs);
-
-         --  The exponent is the scaling factor adjusted for the digits
-         --  that we output after the decimal point, since these were
-         --  included in the scaled digits that we output.
-
-         Expon := Scale + NFrac;
-
-         Set ('E');
-         Ndigs := 0;
+         --  Use Unsigned routine if possible, since on 32-bit machines it will
+         --  be significantly more efficient than the Long_Long_Unsigned one.
 
-         if Expon >= 0 then
-            Set ('+');
-            Set_Image_Unsigned (Unsigned (Expon), Digs, Ndigs);
-         else
-            Set ('-');
-            Set_Image_Unsigned (Unsigned (-Expon), Digs, Ndigs);
+         if X <= Long_Long_Float (Unsigned'Last) then
+            declare
+               I : constant Unsigned :=
+                     Unsigned (Long_Long_Float'Truncation (X));
+            begin
+               Set_Image_Unsigned (I, Digs, Ndigs);
+            end;
+
+         else pragma Assert (X <= Long_Long_Float (LLU'Last));
+            declare
+               I : constant LLU :=
+                     LLU (Long_Long_Float'Truncation (X));
+            begin
+               Set_Image_Long_Long_Unsigned (I, Digs, Ndigs);
+            end;
          end if;
-
-         Set_Zeros (Exp - Ndigs - 1);
-         Set_Digs (1, Ndigs);
       end if;
 
+      Set_Decimal_Digits (Digs, Ndigs, S, P, Scale, Fore, Aft, Exp);
    end Set_Image_Real;
 
 end System.Img_Real;
diff --git a/gcc/ada/libgnat/s-imgrea.ads b/gcc/ada/libgnat/s-imgrea.ads
index 170cb4f936e3..2da869bdbeec 100644
--- a/gcc/ada/libgnat/s-imgrea.ads
+++ b/gcc/ada/libgnat/s-imgrea.ads
@@ -63,7 +63,7 @@ package System.Img_Real is
 
    procedure Set_Image_Real
      (V    : Long_Long_Float;
-      S    : out String;
+      S    : in out String;
       P    : in out Natural;
       Fore : Natural;
       Aft  : Natural;
diff --git a/gcc/ada/libgnat/s-imguti.adb b/gcc/ada/libgnat/s-imguti.adb
index f8370c27f7db..e86be4923fd3 100644
--- a/gcc/ada/libgnat/s-imguti.adb
+++ b/gcc/ada/libgnat/s-imguti.adb
@@ -400,4 +400,85 @@ package body System.Img_Util is
       end if;
    end Set_Decimal_Digits;
 
+   --------------------------------
+   -- Set_Floating_Invalid_Value --
+   --------------------------------
+
+   procedure Set_Floating_Invalid_Value
+     (V    : Floating_Invalid_Value;
+      S    : out String;
+      P    : in out Natural;
+      Fore : Natural;
+      Aft  : Natural;
+      Exp  : Natural)
+   is
+      procedure Set (C : Character);
+      --  Sets character C in output buffer
+
+      procedure Set_Special_Fill (N : Natural);
+      --  After outputting +Inf, -Inf or NaN, this routine fills out the
+      --  rest of the field with * characters. The argument is the number
+      --  of characters output so far (either 3 or 4)
+
+      ---------
+      -- Set --
+      ---------
+
+      procedure Set (C : Character) is
+      begin
+         pragma Assert (P in S'First - 1 .. S'Last - 1);
+         --  No check is done as documented in the header: updating P to point
+         --  to the last character stored, the caller promises that the buffer
+         --  is large enough and no check is made for this. Constraint_Error
+         --  will not necessarily be raised if this requirement is violated,
+         --  since it is perfectly valid to compile this unit with checks off.
+
+         P := P + 1;
+         S (P) := C;
+      end Set;
+
+      ----------------------
+      -- Set_Special_Fill --
+      ----------------------
+
+      procedure Set_Special_Fill (N : Natural) is
+      begin
+         if Exp /= 0 then
+            for J in N + 1 .. Fore + 1 + Aft + 1 + Exp loop
+               Set ('*');
+            end loop;
+
+         else
+            for J in N + 1 .. Fore + 1 + Aft loop
+               Set ('*');
+            end loop;
+         end if;
+      end Set_Special_Fill;
+
+   --  Start of processing for Set_Floating_Invalid_Value
+
+   begin
+      case V is
+         when Minus_Infinity =>
+            Set ('-');
+            Set ('I');
+            Set ('n');
+            Set ('f');
+            Set_Special_Fill (4);
+
+         when Infinity =>
+            Set ('+');
+            Set ('I');
+            Set ('n');
+            Set ('f');
+            Set_Special_Fill (4);
+
+         when Not_A_Number =>
+            Set ('N');
+            Set ('a');
+            Set ('N');
+            Set_Special_Fill (3);
+      end case;
+   end Set_Floating_Invalid_Value;
+
 end System.Img_Util;
diff --git a/gcc/ada/libgnat/s-imguti.ads b/gcc/ada/libgnat/s-imguti.ads
index 99cc51352819..680c0bb8eafd 100644
--- a/gcc/ada/libgnat/s-imguti.ads
+++ b/gcc/ada/libgnat/s-imguti.ads
@@ -58,4 +58,19 @@ package System.Img_Util is
    --  may destroy the value in Digs, which is why Digs is in-out (this happens
    --  if rounding is required).
 
+   type Floating_Invalid_Value is (Minus_Infinity, Infinity, Not_A_Number);
+
+   procedure Set_Floating_Invalid_Value
+     (V    : Floating_Invalid_Value;
+      S    : out String;
+      P    : in out Natural;
+      Fore : Natural;
+      Aft  : Natural;
+      Exp  : Natural);
+   --  Sets the image of a floating-point invalid value, starting at S (P + 1),
+   --  updating P to point to the last character stored. The caller promises
+   --  that the buffer is large enough and therefore no check is made for it.
+   --  Constraint_Error will not necessarily be raised if the requirement is
+   --  violated since it is valid to compile this unit with checks off.
+
 end System.Img_Util;
diff --git a/gcc/ada/libgnat/s-unstyp.ads b/gcc/ada/libgnat/s-unstyp.ads
index 21e79b8b4611..197fd24cfa1b 100644
--- a/gcc/ada/libgnat/s-unstyp.ads
+++ b/gcc/ada/libgnat/s-unstyp.ads
@@ -48,9 +48,6 @@ package System.Unsigned_Types is
    type Long_Long_Unsigned      is mod 2 ** Long_Long_Integer'Size;
    type Long_Long_Long_Unsigned is mod Max_Binary_Modulus;
 
-   type Float_Unsigned          is mod 2 ** Float'Size;
-   --  Used in the implementation of Is_Negative intrinsic (see Exp_Intr)
-
    type Packed_Byte is mod 2 ** 8;
    for Packed_Byte'Size use 8;
    pragma Universal_Aliasing (Packed_Byte);
diff --git a/gcc/ada/rtsfind.ads b/gcc/ada/rtsfind.ads
index 193475f85e1a..3bc36a148a9e 100644
--- a/gcc/ada/rtsfind.ads
+++ b/gcc/ada/rtsfind.ads
@@ -2004,7 +2004,6 @@ package Rtsfind is
      RE_Bits_1,                          -- System.Unsigned_Types
      RE_Bits_2,                          -- System.Unsigned_Types
      RE_Bits_4,                          -- System.Unsigned_Types
-     RE_Float_Unsigned,                  -- System.Unsigned_Types
      RE_Long_Long_Unsigned,              -- System.Unsigned_Types
      RE_Long_Long_Long_Unsigned,         -- System.Unsigned_Types
      RE_Packed_Byte,                     -- System.Unsigned_Types
@@ -3684,7 +3683,6 @@ package Rtsfind is
      RE_Bits_1                           => System_Unsigned_Types,
      RE_Bits_2                           => System_Unsigned_Types,
      RE_Bits_4                           => System_Unsigned_Types,
-     RE_Float_Unsigned                   => System_Unsigned_Types,
      RE_Long_Long_Unsigned               => System_Unsigned_Types,
      RE_Long_Long_Long_Unsigned          => System_Unsigned_Types,
      RE_Packed_Byte                      => System_Unsigned_Types,
diff --git a/gcc/ada/snames.ads-tmpl b/gcc/ada/snames.ads-tmpl
index b431c2c2b7ba..206e915d3957 100644
--- a/gcc/ada/snames.ads-tmpl
+++ b/gcc/ada/snames.ads-tmpl
@@ -1333,7 +1333,6 @@ package Snames is
    Name_Import_Address                   : constant Name_Id := N + $;
    Name_Import_Largest_Value             : constant Name_Id := N + $;
    Name_Import_Value                     : constant Name_Id := N + $;
-   Name_Is_Negative                      : constant Name_Id := N + $;
    Name_Line                             : constant Name_Id := N + $;
    Name_Rotate_Left                      : constant Name_Id := N + $;
    Name_Rotate_Right                     : constant Name_Id := N + $;
-- 
GitLab