[Ada] Fix static computation of 'Succ for floating point without denormals
authorEric Botcazou <ebotcazou@adacore.com>
Mon, 14 Dec 2020 14:58:49 +0000 (15:58 +0100)
committerPierre-Marie de Rodat <derodat@adacore.com>
Thu, 29 Apr 2021 08:00:44 +0000 (04:00 -0400)
gcc/ada/

* eval_fat.adb (Succ): Add a special case for zero if the type does
not support denormalized numbers.  Always use the canonical formula
in other cases and add commentary throughout the function.

gcc/ada/eval_fat.adb

index 8160cba..69ba742 100644 (file)
@@ -729,22 +729,30 @@ package body Eval_Fat is
       New_Frac : T;
 
    begin
+      --  Treat zero as a regular denormalized number if they are supported,
+      --  otherwise return the smallest normalized number.
+
       if UR_Is_Zero (X) then
-         Exp := Emin;
+         if Has_Denormals (RT) then
+            Exp := Emin;
+         else
+            return Scaling (RT, Ureal_1, Emin - 1);
+         end if;
       end if;
 
-      --  Set exponent such that the radix point will be directly following the
-      --  mantissa after scaling.
-
-      if Has_Denormals (RT) or Exp /= Emin then
-         Exp := Exp - Mantissa;
-      else
-         Exp := Exp - 1;
-      end if;
+      --  Multiply the number by 2.0**(Mantissa-Exp) so that the radix point
+      --  will be directly following the mantissa after scaling.
 
+      Exp := Exp - Mantissa;
       Frac := Scaling (RT, X, -Exp);
+
+      --  Round to the neareast integer towards +Inf
+
       New_Frac := Ceiling (RT, Frac);
 
+      --  If the rounding was a NOP, add one, except for -2.0**(Mantissa-1)
+      --  because the exponent is going to be reduced.
+
       if New_Frac = Frac then
          if New_Frac = Scaling (RT, -Ureal_1, Mantissa - 1) then
             New_Frac := New_Frac + Scaling (RT, Ureal_1, Uint_Minus_1);
@@ -753,6 +761,8 @@ package body Eval_Fat is
          end if;
       end if;
 
+      --  Divide back by 2.0**(Mantissa-Exp) to get the final result
+
       return Scaling (RT, New_Frac, Exp);
    end Succ;