diff mbox

[Ada] Fixed-point multiplication in with no floating point

Message ID 20141107134529.GA10745@adacore.com
State New
Headers show

Commit Message

Arnaud Charlet Nov. 7, 2014, 1:45 p.m. UTC
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  <schonberg@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.
diff mbox

Patch

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;