In most cases, the common operations for fixed-point types are implemented
by means of corresponding integer operations, in particular multiplication
and division.  Because scaling is required to go back and forth between
the two representations, the expander needs to control the magnitude of
operands in order to avoid a spurious overflow during the computation.

It turns out that this control is suboptimal for the multiplication, thus
leading to operations of an unnecessarily large magnitude in some cases.

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

gcc/ada/

        * exp_fixd.adb (Build_Double_Divide): Use the RM size of types and
        a more precise estimate for the size of the denominator.
        (Build_Double_Divide_Code): Likewise.
        (Build_Multiply): Use a more precise estimate for the size of the
        result.
        (Build_Scaled_Divide):  Use the RM size of types and a more precise
        estimate for the size of the numerator.
        (Build_Scaled_Divide_Code): Likewise.
diff --git a/gcc/ada/exp_fixd.adb b/gcc/ada/exp_fixd.adb
--- a/gcc/ada/exp_fixd.adb
+++ b/gcc/ada/exp_fixd.adb
@@ -448,15 +448,15 @@ package body Exp_Fixd is
      (N       : Node_Id;
       X, Y, Z : Node_Id) return Node_Id
    is
-      Y_Size : constant Nat := UI_To_Int (Esize (Etype (Y)));
-      Z_Size : constant Nat := UI_To_Int (Esize (Etype (Z)));
+      Y_Size : constant Nat := UI_To_Int (RM_Size (Etype (Y)));
+      Z_Size : constant Nat := UI_To_Int (RM_Size (Etype (Z)));
       Expr   : Node_Id;
 
    begin
       --  If the denominator fits in Max_Integer_Size bits, we can build the
       --  operations directly without causing any intermediate overflow.
 
-      if 2 * Nat'Max (Y_Size, Z_Size) <= System_Max_Integer_Size then
+      if Y_Size + Z_Size <= System_Max_Integer_Size then
          return Build_Divide (N, X, Build_Multiply (N, Y, Z));
 
       --  Otherwise we use the runtime routine
@@ -516,9 +516,9 @@ package body Exp_Fixd is
    is
       Loc    : constant Source_Ptr := Sloc (N);
 
-      X_Size : constant Nat := UI_To_Int (Esize (Etype (X)));
-      Y_Size : constant Nat := UI_To_Int (Esize (Etype (Y)));
-      Z_Size : constant Nat := UI_To_Int (Esize (Etype (Z)));
+      X_Size : constant Nat := UI_To_Int (RM_Size (Etype (X)));
+      Y_Size : constant Nat := UI_To_Int (RM_Size (Etype (Y)));
+      Z_Size : constant Nat := UI_To_Int (RM_Size (Etype (Z)));
 
       QR_Id  : RE_Id;
       QR_Siz : Nat;
@@ -533,7 +533,7 @@ package body Exp_Fixd is
    begin
       --  Find type that will allow computation of denominator
 
-      QR_Siz := Nat'Max (X_Size, 2 * Nat'Max (Y_Size, Z_Size));
+      QR_Siz := Nat'Max (X_Size, Y_Size + Z_Size);
 
       if QR_Siz <= 16 then
          QR_Typ := Standard_Integer_16;
@@ -724,10 +724,10 @@ package body Exp_Fixd is
             end;
          end if;
 
-         --  Now the result size must be at least twice the longer of
-         --  the two sizes, to accommodate all possible results.
+         --  Now the result size must be at least the sum of the two sizes,
+         --  to accommodate all possible results.
 
-         Rsize := 2 * Int'Max (Left_Size, Right_Size);
+         Rsize := Left_Size + Right_Size;
 
          if Rsize <= 8 then
             Result_Type := Standard_Integer_8;
@@ -828,15 +828,15 @@ package body Exp_Fixd is
      (N       : Node_Id;
       X, Y, Z : Node_Id) return Node_Id
    is
-      X_Size : constant Nat := UI_To_Int (Esize (Etype (X)));
-      Y_Size : constant Nat := UI_To_Int (Esize (Etype (Y)));
+      X_Size : constant Nat := UI_To_Int (RM_Size (Etype (X)));
+      Y_Size : constant Nat := UI_To_Int (RM_Size (Etype (Y)));
       Expr   : Node_Id;
 
    begin
       --  If the numerator fits in Max_Integer_Size bits, we can build the
       --  operations directly without causing any intermediate overflow.
 
-      if 2 * Nat'Max (X_Size, Y_Size) <= System_Max_Integer_Size then
+      if X_Size + Y_Size <= System_Max_Integer_Size then
          return Build_Divide (N, Build_Multiply (N, X, Y), Z);
 
       --  Otherwise we use the runtime routine
@@ -893,9 +893,9 @@ package body Exp_Fixd is
    is
       Loc    : constant Source_Ptr := Sloc (N);
 
-      X_Size : constant Nat := UI_To_Int (Esize (Etype (X)));
-      Y_Size : constant Nat := UI_To_Int (Esize (Etype (Y)));
-      Z_Size : constant Nat := UI_To_Int (Esize (Etype (Z)));
+      X_Size : constant Nat := UI_To_Int (RM_Size (Etype (X)));
+      Y_Size : constant Nat := UI_To_Int (RM_Size (Etype (Y)));
+      Z_Size : constant Nat := UI_To_Int (RM_Size (Etype (Z)));
 
       QR_Id  : RE_Id;
       QR_Siz : Nat;
@@ -910,7 +910,7 @@ package body Exp_Fixd is
    begin
       --  Find type that will allow computation of numerator
 
-      QR_Siz := Nat'Max (2 * Nat'Max (X_Size, Y_Size), Z_Size);
+      QR_Siz := Nat'Max (X_Size + Y_Size, Z_Size);
 
       if QR_Siz <= 16 then
          QR_Typ := Standard_Integer_16;


Reply via email to