summaryrefslogtreecommitdiff
path: root/gcc/ada/eval_fat.adb
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/ada/eval_fat.adb')
-rw-r--r--gcc/ada/eval_fat.adb232
1 files changed, 134 insertions, 98 deletions
diff --git a/gcc/ada/eval_fat.adb b/gcc/ada/eval_fat.adb
index fbda4a6611c..f8d14bfe2fa 100644
--- a/gcc/ada/eval_fat.adb
+++ b/gcc/ada/eval_fat.adb
@@ -6,7 +6,7 @@
-- --
-- B o d y --
-- --
--- Copyright (C) 1992-2002 Free Software Foundation, Inc. --
+-- Copyright (C) 1992-2003 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- --
@@ -25,6 +25,7 @@
------------------------------------------------------------------------------
with Einfo; use Einfo;
+with Errout; use Errout;
with Sem_Util; use Sem_Util;
with Ttypef; use Ttypef;
with Targparm; use Targparm;
@@ -72,10 +73,6 @@ package body Eval_Fat is
-- using biased rounding (halfway cases round away from zero), round to
-- even, a floor operation or a ceiling operation depending on the setting
-- of Mode (see corresponding descriptions in Urealp).
- --
- -- In case rounding was specified, Rounding_Was_Biased is set True
- -- if the input was indeed halfway between to machine numbers and
- -- got rounded away from zero to an odd number.
function Eps_Model (RT : R) return T;
-- Return the smallest model number of R.
@@ -83,8 +80,11 @@ package body Eval_Fat is
function Eps_Denorm (RT : R) return T;
-- Return the smallest denormal of type R.
+ function Machine_Emin (RT : R) return Int;
+ -- Return value of the Machine_Emin attribute
+
function Machine_Mantissa (RT : R) return Nat;
- -- Get value of machine mantissa
+ -- Return value of the Machine_Mantissa attribute
--------------
-- Adjacent --
@@ -396,8 +396,6 @@ package body Eval_Fat is
-- Determine correct rounding based on the remainder
-- which is in N and the divisor D.
- Rounding_Was_Biased := False; -- Until proven otherwise
-
case Mode is
when Round_Even =>
@@ -420,10 +418,6 @@ package body Eval_Fat is
if N * 2 >= D then
Fraction := Fraction + 1;
-
- Rounding_Was_Biased := Even and then N * 2 = D;
- -- Check for the case where the result is actually
- -- different from Round_Even.
end if;
when Ceiling =>
@@ -451,54 +445,9 @@ package body Eval_Fat is
----------------
function Eps_Denorm (RT : R) return T is
- Digs : constant UI := Digits_Value (RT);
- Emin : Int;
- Mant : Int;
-
begin
- if Vax_Float (RT) then
- if Digs = VAXFF_Digits then
- Emin := VAXFF_Machine_Emin;
- Mant := VAXFF_Machine_Mantissa;
-
- elsif Digs = VAXDF_Digits then
- Emin := VAXDF_Machine_Emin;
- Mant := VAXDF_Machine_Mantissa;
-
- else
- pragma Assert (Digs = VAXGF_Digits);
- Emin := VAXGF_Machine_Emin;
- Mant := VAXGF_Machine_Mantissa;
- end if;
-
- elsif Is_AAMP_Float (RT) then
- if Digs = AAMPS_Digits then
- Emin := AAMPS_Machine_Emin;
- Mant := AAMPS_Machine_Mantissa;
-
- else
- pragma Assert (Digs = AAMPL_Digits);
- Emin := AAMPL_Machine_Emin;
- Mant := AAMPL_Machine_Mantissa;
- end if;
-
- else
- if Digs = IEEES_Digits then
- Emin := IEEES_Machine_Emin;
- Mant := IEEES_Machine_Mantissa;
-
- elsif Digs = IEEEL_Digits then
- Emin := IEEEL_Machine_Emin;
- Mant := IEEEL_Machine_Mantissa;
-
- else
- pragma Assert (Digs = IEEEX_Digits);
- Emin := IEEEX_Machine_Emin;
- Mant := IEEEX_Machine_Mantissa;
- end if;
- end if;
-
- return Float_Radix ** UI_From_Int (Emin - Mant);
+ return Float_Radix ** UI_From_Int
+ (Machine_Emin (RT) - Machine_Mantissa (RT));
end Eps_Denorm;
---------------
@@ -506,45 +455,8 @@ package body Eval_Fat is
---------------
function Eps_Model (RT : R) return T is
- Digs : constant UI := Digits_Value (RT);
- Emin : Int;
-
begin
- if Vax_Float (RT) then
- if Digs = VAXFF_Digits then
- Emin := VAXFF_Machine_Emin;
-
- elsif Digs = VAXDF_Digits then
- Emin := VAXDF_Machine_Emin;
-
- else
- pragma Assert (Digs = VAXGF_Digits);
- Emin := VAXGF_Machine_Emin;
- end if;
-
- elsif Is_AAMP_Float (RT) then
- if Digs = AAMPS_Digits then
- Emin := AAMPS_Machine_Emin;
-
- else
- pragma Assert (Digs = AAMPL_Digits);
- Emin := AAMPL_Machine_Emin;
- end if;
-
- else
- if Digs = IEEES_Digits then
- Emin := IEEES_Machine_Emin;
-
- elsif Digs = IEEEL_Digits then
- Emin := IEEEL_Machine_Emin;
-
- else
- pragma Assert (Digs = IEEEX_Digits);
- Emin := IEEEX_Machine_Emin;
- end if;
- end if;
-
- return Float_Radix ** UI_From_Int (Emin);
+ return Float_Radix ** UI_From_Int (Machine_Emin (RT));
end Eps_Model;
--------------
@@ -624,19 +536,143 @@ package body Eval_Fat is
-- Machine --
-------------
- function Machine (RT : R; X : T; Mode : Rounding_Mode) return T is
+ function Machine
+ (RT : R;
+ X : T;
+ Mode : Rounding_Mode;
+ Enode : Node_Id)
+ return T
+ is
+ pragma Warnings (Off, Enode); -- not yet referenced
+
X_Frac : T;
X_Exp : UI;
+ Emin : constant UI := UI_From_Int (Machine_Emin (RT));
begin
if UR_Is_Zero (X) then
return X;
+
else
Decompose (RT, X, X_Frac, X_Exp, Mode);
+
+ -- Case of denormalized number or (gradual) underflow
+
+ -- A denormalized number is one with the minimum exponent Emin, but
+ -- that breaks the assumption that the first digit of the mantissa
+ -- is a one. This allows the first non-zero digit to be in any
+ -- of the remaining Mant - 1 spots. The gap between subsequent
+ -- denormalized numbers is the same as for the smallest normalized
+ -- numbers. However, the number of significant digits left decreases
+ -- as a result of the mantissa now having leading seros.
+
+ if X_Exp < Emin then
+ declare
+ Emin_Den : constant UI :=
+ UI_From_Int
+ (Machine_Emin (RT) - Machine_Mantissa (RT) + 1);
+ begin
+ if X_Exp < Emin_Den or not Denorm_On_Target then
+ if UR_Is_Negative (X) then
+ Error_Msg_N
+ ("floating-point value underflows to -0.0?", Enode);
+ return Ureal_M_0;
+
+ else
+ Error_Msg_N
+ ("floating-point value underflows to 0.0?", Enode);
+ return Ureal_0;
+ end if;
+
+ elsif Denorm_On_Target then
+
+ -- Emin - Mant <= X_Exp < Emin, so result is denormal.
+ -- Handle gradual underflow by first computing the
+ -- number of significant bits still available for the
+ -- mantissa and then truncating the fraction to this
+ -- number of bits.
+
+ -- If this value is different from the original
+ -- fraction, precision is lost due to gradual underflow.
+
+ -- We probably should round here and prevent double
+ -- rounding as a result of first rounding to a model
+ -- number and then to a machine number. However, this
+ -- is an extremely rare case that is not worth the extra
+ -- complexity. In any case, a warning is issued in cases
+ -- where gradual underflow occurs.
+
+ declare
+ Denorm_Sig_Bits : constant UI := X_Exp - Emin_Den + 1;
+
+ X_Frac_Denorm : constant T := UR_From_Components
+ (UR_Trunc (Scaling (RT, abs X_Frac, Denorm_Sig_Bits)),
+ Denorm_Sig_Bits,
+ Radix,
+ UR_Is_Negative (X));
+
+ begin
+ if X_Frac_Denorm /= X_Frac then
+ Error_Msg_N
+ ("gradual underflow causes loss of precision?",
+ Enode);
+ X_Frac := X_Frac_Denorm;
+ end if;
+ end;
+ end if;
+ end;
+ end if;
+
return Scaling (RT, X_Frac, X_Exp);
end if;
end Machine;
+ ------------------
+ -- Machine_Emin --
+ ------------------
+
+ function Machine_Emin (RT : R) return Int is
+ Digs : constant UI := Digits_Value (RT);
+ Emin : Int;
+
+ begin
+ if Vax_Float (RT) then
+ if Digs = VAXFF_Digits then
+ Emin := VAXFF_Machine_Emin;
+
+ elsif Digs = VAXDF_Digits then
+ Emin := VAXDF_Machine_Emin;
+
+ else
+ pragma Assert (Digs = VAXGF_Digits);
+ Emin := VAXGF_Machine_Emin;
+ end if;
+
+ elsif Is_AAMP_Float (RT) then
+ if Digs = AAMPS_Digits then
+ Emin := AAMPS_Machine_Emin;
+
+ else
+ pragma Assert (Digs = AAMPL_Digits);
+ Emin := AAMPL_Machine_Emin;
+ end if;
+
+ else
+ if Digs = IEEES_Digits then
+ Emin := IEEES_Machine_Emin;
+
+ elsif Digs = IEEEL_Digits then
+ Emin := IEEEL_Machine_Emin;
+
+ else
+ pragma Assert (Digs = IEEEX_Digits);
+ Emin := IEEEX_Machine_Emin;
+ end if;
+ end if;
+
+ return Emin;
+ end Machine_Emin;
+
----------------------
-- Machine_Mantissa --
----------------------