OSDN Git Service

2008-03-24 Ralf Wildenhues <Ralf.Wildenhues@gmx.de>
[pf3gnuchains/gcc-fork.git] / gcc / ada / exp_fixd.adb
index 79f43b1..66c413e 100644 (file)
@@ -6,18 +6,17 @@
 --                                                                          --
 --                                 B o d y                                  --
 --                                                                          --
---          Copyright (C) 1992-2001 Free Software Foundation, Inc.          --
+--          Copyright (C) 1992-2007, 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- --
--- ware  Foundation;  either version 2,  or (at your option) any later ver- --
+-- ware  Foundation;  either version 3,  or (at your option) any later ver- --
 -- sion.  GNAT is distributed in the hope that it will be useful, but WITH- --
 -- OUT ANY WARRANTY;  without even the  implied warranty of MERCHANTABILITY --
 -- or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License --
 -- for  more details.  You should have  received  a copy of the GNU General --
--- Public License  distributed with GNAT;  see file COPYING.  If not, write --
--- to  the Free Software Foundation,  59 Temple Place - Suite 330,  Boston, --
--- MA 02111-1307, USA.                                                      --
+-- Public License  distributed with GNAT; see file COPYING3.  If not, go to --
+-- http://www.gnu.org/licenses for a complete copy of the license.          --
 --                                                                          --
 -- GNAT was originally developed  by the GNAT team at  New York University. --
 -- Extensive contributions were provided by Ada Core Technologies Inc.      --
@@ -30,7 +29,6 @@ with Einfo;    use Einfo;
 with Exp_Util; use Exp_Util;
 with Nlists;   use Nlists;
 with Nmake;    use Nmake;
-with Restrict; use Restrict;
 with Rtsfind;  use Rtsfind;
 with Sem;      use Sem;
 with Sem_Eval; use Sem_Eval;
@@ -39,7 +37,6 @@ with Sem_Util; use Sem_Util;
 with Sinfo;    use Sinfo;
 with Stand;    use Stand;
 with Tbuild;   use Tbuild;
-with Ttypes;   use Ttypes;
 with Uintp;    use Uintp;
 with Urealp;   use Urealp;
 
@@ -63,8 +60,7 @@ package body Exp_Fixd is
      (N    : Node_Id;
       Typ  : Entity_Id;
       Expr : Node_Id;
-      Rchk : Boolean := False)
-      return Node_Id;
+      Rchk : Boolean := False) return Node_Id;
    --  Build an expression that converts the expression Expr to type Typ,
    --  taking the source location from Sloc (N). If the conversions involve
    --  fixed-point types, then the Conversion_OK flag will be set so that the
@@ -74,21 +70,19 @@ package body Exp_Fixd is
 
    function Build_Divide (N : Node_Id; L, R : Node_Id) return Node_Id;
    --  Builds an N_Op_Divide node from the given left and right operand
-   --  expressions, using the source location from Sloc (N). The operands
-   --  are either both Long_Long_Float, in which case Build_Divide differs
-   --  from Make_Op_Divide only in that the Etype of the resulting node is
-   --  set (to Long_Long_Float), or they can be integer types. In this case
-   --  the integer types need not be the same, and Build_Divide converts
-   --  the operand with the smaller sized type to match the type of the
-   --  other operand and sets this as the result type. The Rounded_Result
-   --  flag of the result in this case is set from the Rounded_Result flag
-   --  of node N. On return, the resulting node is analyzed, and has its
-   --  Etype set.
+   --  expressions, using the source location from Sloc (N). The operands are
+   --  either both Universal_Real, in which case Build_Divide differs from
+   --  Make_Op_Divide only in that the Etype of the resulting node is set (to
+   --  Universal_Real), or they can be integer types. In this case the integer
+   --  types need not be the same, and Build_Divide converts the operand with
+   --  the smaller sized type to match the type of the other operand and sets
+   --  this as the result type. The Rounded_Result flag of the result in this
+   --  case is set from the Rounded_Result flag of node N. On return, the
+   --  resulting node is analyzed, and has its Etype set.
 
    function Build_Double_Divide
      (N       : Node_Id;
-      X, Y, Z : Node_Id)
-      return    Node_Id;
+      X, Y, Z : Node_Id) return Node_Id;
    --  Returns a node corresponding to the value X/(Y*Z) using the source
    --  location from Sloc (N). The division is rounded if the Rounded_Result
    --  flag of N is set. The integer types of X, Y, Z may be different. On
@@ -102,37 +96,35 @@ package body Exp_Fixd is
    --  Generates a sequence of code for determining the quotient and remainder
    --  of the division X/(Y*Z), using the source location from Sloc (N).
    --  Entities of appropriate types are allocated for the quotient and
-   --  remainder and returned in Qnn and Rnn. The result is rounded if
-   --  the Rounded_Result flag of N is set. The Etype fields of Qnn and Rnn
-   --  are appropriately set on return.
+   --  remainder and returned in Qnn and Rnn. The result is rounded if the
+   --  Rounded_Result flag of N is set. The Etype fields of Qnn and Rnn are
+   --  appropriately set on return.
 
    function Build_Multiply (N : Node_Id; L, R : Node_Id) return Node_Id;
    --  Builds an N_Op_Multiply node from the given left and right operand
-   --  expressions, using the source location from Sloc (N). The operands
-   --  are either both Long_Long_Float, in which case Build_Divide differs
-   --  from Make_Op_Multiply only in that the Etype of the resulting node is
-   --  set (to Long_Long_Float), or they can be integer types. In this case
-   --  the integer types need not be the same, and Build_Multiply chooses
-   --  a type long enough to hold the product (i.e. twice the size of the
-   --  longer of the two operand types), and both operands are converted
-   --  to this type. The Etype of the result is also set to this value.
-   --  However, the result can never overflow Integer_64, so this is the
-   --  largest type that is ever generated. On return, the resulting node
-   --  is analyzed and has its Etype set.
+   --  expressions, using the source location from Sloc (N). The operands are
+   --  either both Universal_Real, in which case Build_Divide differs from
+   --  Make_Op_Multiply only in that the Etype of the resulting node is set (to
+   --  Universal_Real), or they can be integer types. In this case the integer
+   --  types need not be the same, and Build_Multiply chooses a type long
+   --  enough to hold the product (i.e. twice the size of the longer of the two
+   --  operand types), and both operands are converted to this type. The Etype
+   --  of the result is also set to this value. However, the result can never
+   --  overflow Integer_64, so this is the largest type that is ever generated.
+   --  On return, the resulting node is analyzed and has its Etype set.
 
    function Build_Rem (N : Node_Id; L, R : Node_Id) return Node_Id;
    --  Builds an N_Op_Rem node from the given left and right operand
-   --  expressions, using the source location from Sloc (N). The operands
-   --  are both integer types, which need not be the same. Build_Rem
-   --  converts the operand with the smaller sized type to match the type
-   --  of the other operand and sets this as the result type. The result
-   --  is never rounded (rem operations cannot be rounded in any case!)
-   --  On return, the resulting node is analyzed and has its Etype set.
+   --  expressions, using the source location from Sloc (N). The operands are
+   --  both integer types, which need not be the same. Build_Rem converts the
+   --  operand with the smaller sized type to match the type of the other
+   --  operand and sets this as the result type. The result is never rounded
+   --  (rem operations cannot be rounded in any case!) On return, the resulting
+   --  node is analyzed and has its Etype set.
 
    function Build_Scaled_Divide
      (N       : Node_Id;
-      X, Y, Z : Node_Id)
-      return    Node_Id;
+      X, Y, Z : Node_Id) return Node_Id;
    --  Returns a node corresponding to the value X*Y/Z using the source
    --  location from Sloc (N). The division is rounded if the Rounded_Result
    --  flag of N is set. The integer types of X, Y, Z may be different. On
@@ -185,38 +177,42 @@ package body Exp_Fixd is
 
    function Fpt_Value (N : Node_Id) return Node_Id;
    --  Given an operand of fixed-point operation, return an expression that
-   --  represents the corresponding Long_Long_Float value. The expression
+   --  represents the corresponding Universal_Real value. The expression
    --  can be of integer type, floating-point type, or fixed-point type.
    --  The expression returned is neither analyzed and resolved. The Etype
-   --  of the result is properly set (to Long_Long_Float).
+   --  of the result is properly set (to Universal_Real).
 
-   function Integer_Literal (N : Node_Id; V : Uint) return Node_Id;
+   function Integer_Literal
+     (N        : Node_Id;
+      V        : Uint;
+      Negative : Boolean := False) return Node_Id;
    --  Given a non-negative universal integer value, build a typed integer
    --  literal node, using the smallest applicable standard integer type. If
-   --  the value exceeds 2**63-1, the largest value allowed for perfect result
-   --  set scaling factors (see RM G.2.3(22)), then Empty is returned. The
-   --  node N provides the Sloc value for the constructed literal. The Etype
-   --  of the resulting literal is correctly set, and it is marked as analyzed.
+   --  and only if Negative is true a negative literal is built. If V exceeds
+   --  2**63-1, the largest value allowed for perfect result set scaling
+   --  factors (see RM G.2.3(22)), then Empty is returned. The node N provides
+   --  the Sloc value for the constructed literal. The Etype of the resulting
+   --  literal is correctly set, and it is marked as analyzed.
 
    function Real_Literal (N : Node_Id; V : Ureal) return Node_Id;
    --  Build a real literal node from the given value, the Etype of the
-   --  returned node is set to Long_Long_Float, since all floating-point
-   --  arithmetic operations that we construct use Long_Long_Float
+   --  returned node is set to Universal_Real, since all floating-point
+   --  arithmetic operations that we construct use Universal_Real
 
    function Rounded_Result_Set (N : Node_Id) return Boolean;
    --  Returns True if N is a node that contains the Rounded_Result flag
-   --  and if the flag is true.
+   --  and if the flag is true or the target type is an integer type.
 
    procedure Set_Result (N : Node_Id; Expr : Node_Id; Rchk : Boolean := False);
    --  N is the node for the current conversion, division or multiplication
-   --  operation, and Expr is an expression representing the result. Expr
-   --  may be of floating-point or integer type. If the operation result
-   --  is fixed-point, then the value of Expr is in units of small of the
-   --  result type (i.e. small's have already been dealt with). The result
-   --  of the call is to replace N by an appropriate conversion to the
-   --  result type, dealing with rounding for the decimal types case. The
-   --  node is then analyzed and resolved using the result type. If Rchk
-   --  is True, then Do_Range_Check is set in the resulting conversion.
+   --  operation, and Expr is an expression representing the result. Expr may
+   --  be of floating-point or integer type. If the operation result is fixed-
+   --  point, then the value of Expr is in units of small of the result type
+   --  (i.e. small's have already been dealt with). The result of the call is
+   --  to replace N by an appropriate conversion to the result type, dealing
+   --  with rounding for the decimal types case. The node is then analyzed and
+   --  resolved using the result type. If Rchk is True, then Do_Range_Check is
+   --  set in the resulting conversion.
 
    ----------------------
    -- Build_Conversion --
@@ -226,8 +222,7 @@ package body Exp_Fixd is
      (N    : Node_Id;
       Typ  : Entity_Id;
       Expr : Node_Id;
-      Rchk : Boolean := False)
-      return Node_Id
+      Rchk : Boolean := False) return Node_Id
    is
       Loc    : constant Source_Ptr := Sloc (N);
       Result : Node_Id;
@@ -298,7 +293,6 @@ package body Exp_Fixd is
 
       Set_Etype (Result, Typ);
       return Result;
-
    end Build_Conversion;
 
    ------------------
@@ -316,11 +310,11 @@ package body Exp_Fixd is
       --  Deal with floating-point case first
 
       if Is_Floating_Point_Type (Left_Type) then
-         pragma Assert (Left_Type = Standard_Long_Long_Float);
-         pragma Assert (Right_Type = Standard_Long_Long_Float);
+         pragma Assert (Left_Type = Universal_Real);
+         pragma Assert (Right_Type = Universal_Real);
 
          Rnode := Make_Op_Divide (Loc, L, R);
-         Result_Type := Standard_Long_Long_Float;
+         Result_Type := Universal_Real;
 
       --  Integer and fixed-point cases
 
@@ -386,7 +380,6 @@ package body Exp_Fixd is
       end if;
 
       return Rnode;
-
    end Build_Divide;
 
    -------------------------
@@ -395,21 +388,13 @@ package body Exp_Fixd is
 
    function Build_Double_Divide
      (N       : Node_Id;
-      X, Y, Z : Node_Id)
-      return    Node_Id
+      X, Y, Z : Node_Id) return Node_Id
    is
       Y_Size : constant Int := UI_To_Int (Esize (Etype (Y)));
       Z_Size : constant Int := UI_To_Int (Esize (Etype (Z)));
       Expr   : Node_Id;
 
    begin
-      if Y_Size > System_Word_Size
-           or else
-         Z_Size > System_Word_Size
-      then
-         Disallow_In_No_Run_Time_Mode (N);
-      end if;
-
       --  If denominator fits in 64 bits, we can build the operations directly
       --  without causing any intermediate overflow, so that's what we do!
 
@@ -431,6 +416,8 @@ package body Exp_Fixd is
             Rnn  : Entity_Id;
             Code : List_Id;
 
+            pragma Warnings (Off, Rnn);
+
          begin
             Build_Double_Divide_Code (N, X, Y, Z, Qnn, Rnn, Code);
             Insert_Actions (N, Code);
@@ -570,11 +557,7 @@ package body Exp_Fixd is
       --  call the runtime routine to compute the quotient and remainder
 
       else
-         if Rounded_Result_Set (N) then
-            Rnd := Standard_True;
-         else
-            Rnd := Standard_False;
-         end if;
+         Rnd := Boolean_Literals (Rounded_Result_Set (N));
 
          Code := New_List (
            Make_Object_Declaration (Loc,
@@ -595,7 +578,6 @@ package body Exp_Fixd is
                New_Occurrence_Of (Rnn, Loc),
                New_Occurrence_Of (Rnd, Loc))));
       end if;
-
    end Build_Double_Divide_Code;
 
    --------------------
@@ -606,6 +588,8 @@ package body Exp_Fixd is
       Loc         : constant Source_Ptr := Sloc (N);
       Left_Type   : constant Entity_Id  := Etype (L);
       Right_Type  : constant Entity_Id  := Etype (R);
+      Left_Size   : Int;
+      Right_Size  : Int;
       Rsize       : Int;
       Result_Type : Entity_Id;
       Rnode       : Node_Id;
@@ -614,10 +598,10 @@ package body Exp_Fixd is
       --  Deal with floating-point case first
 
       if Is_Floating_Point_Type (Left_Type) then
-         pragma Assert (Left_Type = Standard_Long_Long_Float);
-         pragma Assert (Right_Type = Standard_Long_Long_Float);
+         pragma Assert (Left_Type = Universal_Real);
+         pragma Assert (Right_Type = Universal_Real);
 
-         Result_Type := Standard_Long_Long_Float;
+         Result_Type := Universal_Real;
          Rnode := Make_Op_Multiply (Loc, L, R);
 
       --  Integer and fixed-point cases
@@ -634,11 +618,54 @@ package body Exp_Fixd is
             return R;
          end if;
 
-         --  Otherwise we use a type that is at least twice the longer
-         --  of the two sizes.
+         --  Otherwise we need to figure out the correct result type size
+         --  First figure out the effective sizes of the operands. Normally
+         --  the effective size of an operand is the RM_Size of the operand.
+         --  But a special case arises with operands whose size is known at
+         --  compile time. In this case, we can use the actual value of the
+         --  operand to get its size if it would fit in 8 or 16 bits.
+
+         --  Note: if both operands are known at compile time (can that
+         --  happen?) and both were equal to the power of 2, then we would
+         --  be one bit off in this test, so for the left operand, we only
+         --  go up to the power of 2 - 1. This ensures that we do not get
+         --  this anomalous case, and in practice the right operand is by
+         --  far the more likely one to be the constant.
+
+         Left_Size := UI_To_Int (RM_Size (Left_Type));
+
+         if Compile_Time_Known_Value (L) then
+            declare
+               Val : constant Uint := Expr_Value (L);
+
+            begin
+               if Val < Int'(2 ** 8) then
+                  Left_Size := 8;
+               elsif Val < Int'(2 ** 16) then
+                  Left_Size := 16;
+               end if;
+            end;
+         end if;
+
+         Right_Size := UI_To_Int (RM_Size (Right_Type));
 
-         Rsize := 2 * Int'Max (UI_To_Int (Esize (Left_Type)),
-                               UI_To_Int (Esize (Right_Type)));
+         if Compile_Time_Known_Value (R) then
+            declare
+               Val : constant Uint := Expr_Value (R);
+
+            begin
+               if Val <= Int'(2 ** 8) then
+                  Right_Size := 8;
+               elsif Val <= Int'(2 ** 16) then
+                  Right_Size := 16;
+               end if;
+            end;
+         end if;
+
+         --  Now the result size must be at least twice the longer of
+         --  the two sizes, to accommodate all possible results.
+
+         Rsize := 2 * Int'Max (Left_Size, Right_Size);
 
          if Rsize <= 8 then
             Result_Type := Standard_Integer_8;
@@ -650,10 +677,6 @@ package body Exp_Fixd is
             Result_Type := Standard_Integer_32;
 
          else
-            if Rsize > System_Word_Size then
-               Disallow_In_No_Run_Time_Mode (N);
-            end if;
-
             Result_Type := Standard_Integer_64;
          end if;
 
@@ -754,8 +777,7 @@ package body Exp_Fixd is
 
    function Build_Scaled_Divide
      (N       : Node_Id;
-      X, Y, Z : Node_Id)
-      return    Node_Id
+      X, Y, Z : Node_Id) return Node_Id
    is
       X_Size : constant Int := UI_To_Int (Esize (Etype (X)));
       Y_Size : constant Int := UI_To_Int (Esize (Etype (Y)));
@@ -783,6 +805,8 @@ package body Exp_Fixd is
             Rnn  : Entity_Id;
             Code : List_Id;
 
+            pragma Warnings (Off, Rnn);
+
          begin
             Build_Scaled_Divide_Code (N, X, Y, Z, Qnn, Rnn, Code);
             Insert_Actions (N, Code);
@@ -915,11 +939,7 @@ package body Exp_Fixd is
       --  call the runtime routine to compute the quotient and remainder
 
       else
-         if Rounded_Result_Set (N) then
-            Rnd := Standard_True;
-         else
-            Rnd := Standard_False;
-         end if;
+         Rnd := Boolean_Literals (Rounded_Result_Set (N));
 
          Code := New_List (
            Make_Object_Declaration (Loc,
@@ -941,7 +961,7 @@ package body Exp_Fixd is
                New_Occurrence_Of (Rnd, Loc))));
       end if;
 
-      --  Set type of result, for use in caller.
+      --  Set type of result, for use in caller
 
       Set_Etype (Qnn, QR_Typ);
    end Build_Scaled_Divide_Code;
@@ -1006,7 +1026,7 @@ package body Exp_Fixd is
       --  would lose precision).
 
       if Frac_Den = 1 then
-         Lit_Int := Integer_Literal (N, Frac_Num);
+         Lit_Int := Integer_Literal (N, Frac_Num); -- always positive
 
          if Present (Lit_Int) then
             Set_Result (N, Build_Scaled_Divide (N, Left, Lit_Int, Right));
@@ -1022,7 +1042,7 @@ package body Exp_Fixd is
       --  divisions), and we don't get inaccuracies from double rounding.
 
       elsif Frac_Num = 1 then
-         Lit_Int := Integer_Literal (N, Frac_Den);
+         Lit_Int := Integer_Literal (N, Frac_Den); -- always positive
 
          if Present (Lit_Int) then
             Set_Result (N, Build_Double_Divide (N, Left, Right, Lit_Int));
@@ -1036,7 +1056,6 @@ package body Exp_Fixd is
         Build_Multiply (N,
           Build_Divide (N, Fpt_Value (Left), Fpt_Value (Right)),
           Real_Literal (N, Frac)));
-
    end Do_Divide_Fixed_Fixed;
 
    -------------------------------
@@ -1071,7 +1090,7 @@ package body Exp_Fixd is
    --  is an integer or the reciprocal of an integer, and for
    --  implementation efficiency we need the smallest such K.
 
-   --  First we reduce the left fraction to lowest terms.
+   --  First we reduce the left fraction to lowest terms
 
    --    If numerator = 1, then for K = 1, the small ratio is the reciprocal
    --    of an integer, and this is clearly the minimum K case, so set K = 1,
@@ -1116,7 +1135,7 @@ package body Exp_Fixd is
       --  where the result can be obtained by dividing by this integer value.
 
       if Frac_Num = 1 then
-         Lit_Int := Integer_Literal (N, Frac_Den);
+         Lit_Int := Integer_Literal (N, Frac_Den, UR_Is_Negative (Frac));
 
          if Present (Lit_Int) then
             Set_Result (N, Build_Divide (N, Left, Lit_Int));
@@ -1131,8 +1150,8 @@ package body Exp_Fixd is
       --  would lose precision).
 
       else
-         Lit_Int := Integer_Literal (N, Frac_Num);
-         Lit_K   := Integer_Literal (N, Frac_Den);
+         Lit_Int := Integer_Literal (N, Frac_Num, UR_Is_Negative (Frac));
+         Lit_K   := Integer_Literal (N, Frac_Den, False);
 
          if Present (Lit_Int) and then Present (Lit_K) then
             Set_Result (N, Build_Scaled_Divide (N, Left, Lit_Int, Lit_K));
@@ -1152,7 +1171,6 @@ package body Exp_Fixd is
 
       Set_Result (N,
         Build_Multiply (N, Fpt_Value (Left), Real_Literal (N, Frac)));
-
    end Do_Divide_Fixed_Universal;
 
    -------------------------------
@@ -1189,7 +1207,7 @@ package body Exp_Fixd is
    --  is an integer or the reciprocal of an integer, and for
    --  implementation efficiency we need the smallest such K.
 
-   --  First we reduce the left fraction to lowest terms.
+   --  First we reduce the left fraction to lowest terms
 
    --    If denominator = 1, then for K = 1, the small ratio is an integer
    --    (the numerator) and this is clearly the minimum K case, so set K = 1,
@@ -1235,7 +1253,7 @@ package body Exp_Fixd is
       --  can be obtained by dividing this integer by the right operand.
 
       if Frac_Den = 1 then
-         Lit_Int := Integer_Literal (N, Frac_Num);
+         Lit_Int := Integer_Literal (N, Frac_Num, UR_Is_Negative (Frac));
 
          if Present (Lit_Int) then
             Set_Result (N, Build_Divide (N, Lit_Int, Right));
@@ -1250,8 +1268,8 @@ package body Exp_Fixd is
       --  is important (if we divided first, we would lose precision).
 
       else
-         Lit_Int := Integer_Literal (N, Frac_Den);
-         Lit_K   := Integer_Literal (N, Frac_Num);
+         Lit_Int := Integer_Literal (N, Frac_Den, UR_Is_Negative (Frac));
+         Lit_K   := Integer_Literal (N, Frac_Num, False);
 
          if Present (Lit_Int) and then Present (Lit_K) then
             Set_Result (N, Build_Double_Divide (N, Lit_K, Right, Lit_Int));
@@ -1271,7 +1289,6 @@ package body Exp_Fixd is
 
       Set_Result (N,
         Build_Divide (N, Real_Literal (N, Frac), Fpt_Value (Right)));
-
    end Do_Divide_Universal_Fixed;
 
    -----------------------------
@@ -1327,7 +1344,7 @@ package body Exp_Fixd is
       --  the operands, and then multiplying the result by the integer value.
 
       if Frac_Den = 1 then
-         Lit_Int := Integer_Literal (N, Frac_Num);
+         Lit_Int := Integer_Literal (N, Frac_Num); -- always positive
 
          if Present (Lit_Int) then
             Set_Result (N,
@@ -1342,7 +1359,7 @@ package body Exp_Fixd is
       --  divided first, we would lose precision.
 
       elsif Frac_Num = 1 then
-         Lit_Int := Integer_Literal (N, Frac_Den);
+         Lit_Int := Integer_Literal (N, Frac_Den); -- always positive
 
          if Present (Lit_Int) then
             Set_Result (N, Build_Scaled_Divide (N, Left, Right, Lit_Int));
@@ -1356,7 +1373,6 @@ package body Exp_Fixd is
         Build_Multiply (N,
           Build_Multiply (N, Fpt_Value (Left), Fpt_Value (Right)),
           Real_Literal (N, Frac)));
-
    end Do_Multiply_Fixed_Fixed;
 
    ---------------------------------
@@ -1391,15 +1407,16 @@ package body Exp_Fixd is
    --  is an integer or the reciprocal of an integer, and for
    --  implementation efficiency we need the smallest such K.
 
-   --  First we reduce the left fraction to lowest terms.
+   --  First we reduce the left fraction to lowest terms
 
-   --    If denominator = 1, then for K = 1, the small ratio is an
-   --    integer, and this is clearly the minimum K case, so set
-   --    K = 1, Right_Small = Lit_Value.
+   --    If denominator = 1, then for K = 1, the small ratio is an integer, and
+   --    this is clearly the minimum K case, so set
 
-   --    If denominator > 1, then set K to the numerator of the
-   --    fraction, so that the resulting small ratio is the
-   --    reciprocal of the integer (the denominator value).
+   --      K = 1, Right_Small = Lit_Value
+
+   --    If denominator > 1, then set K to the numerator of the fraction, so
+   --    that the resulting small ratio is the reciprocal of the integer (the
+   --    denominator value).
 
    procedure Do_Multiply_Fixed_Universal
      (N           : Node_Id;
@@ -1438,7 +1455,7 @@ package body Exp_Fixd is
       --  be obtained by multiplying by this integer value.
 
       if Frac_Den = 1 then
-         Lit_Int := Integer_Literal (N, Frac_Num);
+         Lit_Int := Integer_Literal (N, Frac_Num, UR_Is_Negative (Frac));
 
          if Present (Lit_Int) then
             Set_Result (N, Build_Multiply (N, Left, Lit_Int));
@@ -1452,7 +1469,7 @@ package body Exp_Fixd is
       --  dividing by the integer value.
 
       else
-         Lit_Int := Integer_Literal (N, Frac_Den);
+         Lit_Int := Integer_Literal (N, Frac_Den, UR_Is_Negative (Frac));
          Lit_K   := Integer_Literal (N, Frac_Num);
 
          if Present (Lit_Int) and then Present (Lit_K) then
@@ -1473,7 +1490,6 @@ package body Exp_Fixd is
 
       Set_Result (N,
         Build_Multiply (N, Fpt_Value (Left), Real_Literal (N, Frac)));
-
    end Do_Multiply_Fixed_Universal;
 
    ---------------------------------
@@ -1528,7 +1544,6 @@ package body Exp_Fixd is
       Ratio_Den   := Norm_Den (Small_Ratio);
 
       if Ratio_Den = 1 then
-
          if Ratio_Num = 1 then
             Set_Result (N, Expr);
             return;
@@ -1560,7 +1575,6 @@ package body Exp_Fixd is
           Fpt_Value (Expr),
           Real_Literal (N, Small_Ratio)),
         Rng_Check);
-
    end Expand_Convert_Fixed_To_Fixed;
 
    -----------------------------------
@@ -1569,7 +1583,7 @@ package body Exp_Fixd is
 
    --  If the small of the fixed type is 1.0, then we simply convert the
    --  integer value directly to the target floating-point type, otherwise
-   --  we first have to multiply by the small, in Long_Long_Float, and then
+   --  we first have to multiply by the small, in Universal_Real, and then
    --  convert the result to the target floating-point type.
 
    procedure Expand_Convert_Fixed_To_Float (N : Node_Id) is
@@ -1654,7 +1668,6 @@ package body Exp_Fixd is
           Fpt_Value (Expr),
           Real_Literal (N, Small)),
         Rng_Check);
-
    end Expand_Convert_Fixed_To_Integer;
 
    -----------------------------------
@@ -1751,7 +1764,6 @@ package body Exp_Fixd is
           Fpt_Value (Expr),
           Real_Literal (N, Ureal_1 / Small)),
         Rng_Check);
-
    end Expand_Convert_Integer_To_Fixed;
 
    --------------------------------
@@ -1801,7 +1813,7 @@ package body Exp_Fixd is
    --  division or multiplication by the appropriate power of 10.
 
    procedure Expand_Decimal_Divide_Call (N : Node_Id) is
-      Loc       : constant Source_Ptr := Sloc (N);
+      Loc : constant Source_Ptr := Sloc (N);
 
       Dividend  : Node_Id := First_Actual (N);
       Divisor   : Node_Id := Next_Actual (Dividend);
@@ -1946,7 +1958,6 @@ package body Exp_Fixd is
               Statements => Stmts)));
 
       Analyze (N);
-
    end Expand_Decimal_Divide_Call;
 
    -----------------------------------------------
@@ -1974,14 +1985,13 @@ package body Exp_Fixd is
       else
          Do_Divide_Fixed_Fixed (N);
       end if;
-
    end Expand_Divide_Fixed_By_Fixed_Giving_Fixed;
 
    -----------------------------------------------
    -- Expand_Divide_Fixed_By_Fixed_Giving_Float --
    -----------------------------------------------
 
-   --  The division is done in long_long_float, and the result is multiplied
+   --  The division is done in Universal_Real, and the result is multiplied
    --  by the small ratio, which is Small (Right) / Small (Left). Special
    --  treatment is required for universal operands, which represent their
    --  own value and do not require conversion.
@@ -2040,7 +2050,6 @@ package body Exp_Fixd is
              Real_Literal (N,
                Small_Value (Left_Type) / Small_Value (Right_Type))));
       end if;
-
    end Expand_Divide_Fixed_By_Fixed_Giving_Float;
 
    -------------------------------------------------
@@ -2050,18 +2059,14 @@ package body Exp_Fixd is
    procedure Expand_Divide_Fixed_By_Fixed_Giving_Integer (N : Node_Id) is
       Left  : constant Node_Id := Left_Opnd (N);
       Right : constant Node_Id := Right_Opnd (N);
-
    begin
       if Etype (Left) = Universal_Real then
          Do_Divide_Universal_Fixed (N);
-
       elsif Etype (Right) = Universal_Real then
          Do_Divide_Fixed_Universal (N);
-
       else
          Do_Divide_Fixed_Fixed (N);
       end if;
-
    end Expand_Divide_Fixed_By_Fixed_Giving_Integer;
 
    -------------------------------------------------
@@ -2074,7 +2079,6 @@ package body Exp_Fixd is
    procedure Expand_Divide_Fixed_By_Integer_Giving_Fixed (N : Node_Id) is
       Left  : constant Node_Id := Left_Opnd (N);
       Right : constant Node_Id := Right_Opnd (N);
-
    begin
       Set_Result (N, Build_Divide (N, Left, Right));
    end Expand_Divide_Fixed_By_Integer_Giving_Fixed;
@@ -2093,9 +2097,12 @@ package body Exp_Fixd is
       --  as a fixed * fixed multiplication, and convert the argument to
       --  the target fixed type.
 
-      procedure Rewrite_Non_Static_Universal (Opnd : Node_Id) is
-         Loc   : constant Source_Ptr := Sloc (N);
+      ----------------------------------
+      -- Rewrite_Non_Static_Universal --
+      ----------------------------------
 
+      procedure Rewrite_Non_Static_Universal (Opnd : Node_Id) is
+         Loc : constant Source_Ptr := Sloc (N);
       begin
          Rewrite (Opnd,
            Make_Type_Conversion (Loc,
@@ -2104,6 +2111,8 @@ package body Exp_Fixd is
          Analyze_And_Resolve (Opnd, Etype (N));
       end Rewrite_Non_Static_Universal;
 
+   --  Start of processing for Expand_Multiply_Fixed_By_Fixed_Giving_Fixed
+
    begin
       --  Suppress expansion of a fixed-by-fixed multiplication if the
       --  operation is supported directly by the target.
@@ -2133,14 +2142,13 @@ package body Exp_Fixd is
       else
          Do_Multiply_Fixed_Fixed (N);
       end if;
-
    end Expand_Multiply_Fixed_By_Fixed_Giving_Fixed;
 
    -------------------------------------------------
    -- Expand_Multiply_Fixed_By_Fixed_Giving_Float --
    -------------------------------------------------
 
-   --  The multiply is done in long_long_float, and the result is multiplied
+   --  The multiply is done in Universal_Real, and the result is multiplied
    --  by the adjustment for the smalls which is Small (Right) * Small (Left).
    --  Special treatment is required for universal operands.
 
@@ -2195,7 +2203,6 @@ package body Exp_Fixd is
              Real_Literal (N,
                Small_Value (Right_Type) * Small_Value (Left_Type))));
       end if;
-
    end Expand_Multiply_Fixed_By_Fixed_Giving_Float;
 
    ---------------------------------------------------
@@ -2205,18 +2212,14 @@ package body Exp_Fixd is
    procedure Expand_Multiply_Fixed_By_Fixed_Giving_Integer (N : Node_Id) is
       Left  : constant Node_Id := Left_Opnd (N);
       Right : constant Node_Id := Right_Opnd (N);
-
    begin
       if Etype (Left) = Universal_Real then
          Do_Multiply_Fixed_Universal (N, Right, Left);
-
       elsif Etype (Right) = Universal_Real then
          Do_Multiply_Fixed_Universal (N, Left, Right);
-
       else
          Do_Multiply_Fixed_Fixed (N);
       end if;
-
    end Expand_Multiply_Fixed_By_Fixed_Giving_Integer;
 
    ---------------------------------------------------
@@ -2256,24 +2259,24 @@ package body Exp_Fixd is
       if Is_Integer_Type (Typ)
         or else Is_Floating_Point_Type (Typ)
       then
-         return
-           Build_Conversion
-             (N, Standard_Long_Long_Float, N);
+         return Build_Conversion (N, Universal_Real, N);
 
       --  Fixed-point case, must get integer value first
 
       else
-         return
-           Build_Conversion (N, Standard_Long_Long_Float, N);
+         return Build_Conversion (N, Universal_Real, N);
       end if;
-
    end Fpt_Value;
 
    ---------------------
    -- Integer_Literal --
    ---------------------
 
-   function Integer_Literal (N : Node_Id; V : Uint) return Node_Id is
+   function Integer_Literal
+     (N        : Node_Id;
+      V        : Uint;
+      Negative : Boolean := False) return Node_Id
+   is
       T : Entity_Id;
       L : Node_Id;
 
@@ -2294,7 +2297,11 @@ package body Exp_Fixd is
          return Empty;
       end if;
 
-      L := Make_Integer_Literal (Sloc (N), V);
+      if Negative then
+         L := Make_Integer_Literal (Sloc (N), UI_Negate (V));
+      else
+         L := Make_Integer_Literal (Sloc (N), V);
+      end if;
 
       --  Set type of result in case used elsewhere (see note at start)
 
@@ -2309,7 +2316,6 @@ package body Exp_Fixd is
 
       Set_Analyzed (L);
       return L;
-
    end Integer_Literal;
 
    ------------------
@@ -2324,7 +2330,7 @@ package body Exp_Fixd is
 
       --  Set type of result in case used elsewhere (see note at start)
 
-      Set_Etype (L, Standard_Long_Long_Float);
+      Set_Etype (L, Universal_Real);
       return L;
    end Real_Literal;
 
@@ -2334,12 +2340,12 @@ package body Exp_Fixd is
 
    function Rounded_Result_Set (N : Node_Id) return Boolean is
       K : constant Node_Kind := Nkind (N);
-
    begin
       if (K = N_Type_Conversion or else
           K = N_Op_Divide       or else
           K = N_Op_Multiply)
-        and then Rounded_Result (N)
+        and then
+          (Rounded_Result (N) or else Is_Integer_Type (Etype (N)))
       then
          return True;
       else
@@ -2375,7 +2381,6 @@ package body Exp_Fixd is
 
       Rewrite (N, Cnode);
       Analyze_And_Resolve (N, Result_Type);
-
    end Set_Result;
 
 end Exp_Fixd;