In the general case, a multiplication of two fixed-point values that yield
an integer type requires the use of floating point operations. When the types
of the operands are identical it is possible to avoid their use by introducing
a temporary of the same type, and performing a conversion to integer in a
separate step. Transformation is useful when floating-point is unavailable
on the target.

The following must compile quietly:

    gcc -c -gnatG t.adb | grep universal_real

---
pragma Restrictions (No_Floating_Point);

Package T is
   type T_Real_64_Bis is
       delta 2.0 ** (-32) range -(2.0 ** 31) .. (2.0 ** 31) - 2.0 ** (-32);
   procedure  Add_Duration_Tst (Dur     : in     T_Real_64_Bis);
end T;
---
Package body T is
   procedure Add_Duration_Tst (Dur     : in     T_Real_64_Bis) is
      c_To_us        : constant T_Real_64_Bis            := 1_000_000.0;
      c_Duration_us1  : constant Integer := Integer (Dur * C_To_Us);
   begin
      null;
   end Add_Duration_Tst;
end T;

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

2014-11-07  Ed Schonberg  <schonb...@adacore.com>

        * exp_fixd.adb (Expand_Multiply_Fixed_By_Fixed_Giving_Integer):
        If the restriction No_Floating_Point is in effect, and the
        operands have the same type, introduce a temporary to hold
        the fixed point result, to prevent the use of floating-point
        operations at run-time.

Index: exp_fixd.adb
===================================================================
--- exp_fixd.adb        (revision 217215)
+++ exp_fixd.adb        (working copy)
@@ -6,7 +6,7 @@
 --                                                                          --
 --                                 B o d y                                  --
 --                                                                          --
---          Copyright (C) 1992-2013, Free Software Foundation, Inc.         --
+--          Copyright (C) 1992-2014, 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- --
@@ -29,6 +29,8 @@
 with Exp_Util; use Exp_Util;
 with Nlists;   use Nlists;
 with Nmake;    use Nmake;
+with Restrict; use Restrict;
+with Rident;   use Rident;
 with Rtsfind;  use Rtsfind;
 with Sem;      use Sem;
 with Sem_Eval; use Sem_Eval;
@@ -2214,13 +2216,41 @@
    ---------------------------------------------------
 
    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);
+      Loc   : constant Source_Ptr := Sloc (N);
+      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, Left => Right, Right => Left);
+
       elsif Etype (Right) = Universal_Real then
          Do_Multiply_Fixed_Universal (N, Left, Right);
+
+      --  If both types are equal and we need to avoid floating point
+      --  instructions, it's worth introducing a temporary with the
+      --  common type, because it may be evaluated more simply without
+      --  the need for run-time use of floating point.
+
+      elsif Etype (Right) = Etype (Left)
+        and then Restriction_Active (No_Floating_Point)
+      then
+         declare
+            Temp : constant Entity_Id := Make_Temporary (Loc, 'F');
+            Mult : constant Node_Id   := Make_Op_Multiply (Loc, Left, Right);
+            Decl : constant Node_Id   :=
+              Make_Object_Declaration (Loc,
+                Defining_Identifier => Temp,
+                Object_Definition   => New_Occurrence_Of (Etype (Right), Loc),
+                Expression          => Mult);
+
+         begin
+            Insert_Action (N, Decl);
+            Rewrite (N,
+              OK_Convert_To (Etype (N), New_Occurrence_Of (Temp, Loc)));
+            Analyze_And_Resolve (N, Standard_Integer);
+         end;
+
       else
          Do_Multiply_Fixed_Fixed (N);
       end if;

Reply via email to