diff mbox

[Ada] Optimization of fixed/fixed operations with compatible 'smalls.

Message ID 20170502083134.GA30617@adacore.com
State New
Headers show

Commit Message

Arnaud Charlet May 2, 2017, 8:31 a.m. UTC
If the Small values of the fixed points involved in a division operation
have common factors, it is possible to simplify the restulting expression,
which will involve numerators and denominators of the corresponding Small
values of the type, as those values are integer literals.

The following must execute quietly:

   gcc -c -gnatDG ec.adb
   grep "30 / 30" ec.adb.dg


with S;
with Interfaces; use Interfaces;

procedure Ec is
   Signal_Denominator : constant := 400;
   type Signal_Type is delta 1.0 / Signal_Denominator
     range -65_536.0 / Signal_Denominator .. 65_535.0 / Signal_Denominator;
   for Signal_Type'Small use 1.0 / Signal_Denominator;

   Delay_30 : constant := 30;

   type Filter_30_Input_Type is delta 1.0 / Signal_Denominator
     range 0.0 .. Signal_Type'Last;
   for Filter_30_Input_Type'Small use 1.0 / Signal_Denominator;
   type Filter_30_Output_Type is delta 1.0 / Signal_Denominator / Delay_30 
     range 0.0 .. Signal_Type'Last;
   for Filter_30_Output_Type'Small use 1.0 / Signal_Denominator / Delay_30;

   type Sum_30_Index_Type is mod Delay_30;

   package Sum_30_Filter is new
     S (Input_Type => Filter_30_Input_Type,
                 Output_Type => Filter_30_Output_Type,
                 Filter_Index_Type => Sum_30_Index_Type);
begin
   null;
end Ec;
---
generic
   type Input_Type is delta <>;
   type Output_Type is delta <>;
   type Filter_Index_Type is mod <>;

package S is
   type Filter_Type is private;

   function Process_Sample (This   : in out Filter_Type;
                            Sample : in     Input_Type)
                           return Output_Type;

private
   type Sum_Filter_Array_Type is array (Filter_Index_Type) of Input_Type;
   type Filter_Type is record
      Samples : Sum_Filter_Array_Type;
      Index : Filter_Index_Type;
      Last_Output : Output_Type;
   end record;
end S;
---
package body S is

   function Process_Sample (This   : in out Filter_Type;
                            Sample : in     Input_Type)
                           return Output_Type is
      --  Initialize output as y(n-1).
      Output : Output_Type := This.Last_Output;

      type Filter_Delay_Type is delta 1.0 range 1.0 .. 65_535.0;
      D : constant Filter_Delay_Type :=
        Filter_Delay_Type (Filter_Index_Type'Last -
                             Filter_Index_Type'First) + 1.0;
   begin
      --  Compute y(n) = y(n-1) + (x(n) - x(n-D)) / D, where D = filter delay.
      Output := Output + (Sample - This.Samples (This.Index)) / D;

      return Output;
   end Process_Sample;
end S;

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

2017-05-02  Ed Schonberg  <schonberg@adacore.com>

	* exp_fixd.adb (Expand_Divide_Fixed_By_Fixed_Giving_Fixed):
	Simplify the expression for a fixed-fixed division to remove
	divisions by constants whenever possible, as an optimization
	for restricted targets.
diff mbox

Patch

Index: exp_fixd.adb
===================================================================
--- exp_fixd.adb	(revision 247461)
+++ exp_fixd.adb	(working copy)
@@ -6,7 +6,7 @@ 
 --                                                                          --
 --                                 B o d y                                  --
 --                                                                          --
---          Copyright (C) 1992-2015, Free Software Foundation, Inc.         --
+--          Copyright (C) 1992-2017, 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- --
@@ -2008,6 +2008,31 @@ 
 
       else
          Do_Divide_Fixed_Fixed (N);
+
+         --  A focused optimization: if after constant folding the
+         --  expression is of the form:  T ((Exp * D) / D), where D is
+         --  a static constant, return  T (Exp). This form will show up
+         --  when D is the denominator of the static expression for the
+         --  'small of fixed-point types involved. This transformation
+         --  removes a division that may be expensive on some targets.
+
+         if Nkind (N) = N_Type_Conversion
+           and then Nkind (Expression (N)) = N_Op_Divide
+         then
+            declare
+               Num : constant Node_Id := Left_Opnd  (Expression (N));
+               Den : constant Node_Id := Right_Opnd (Expression (N));
+
+            begin
+               if Nkind (Den) = N_Integer_Literal
+                 and then Nkind (Num) = N_Op_Multiply
+                 and then Nkind (Right_Opnd (Num)) = N_Integer_Literal
+                 and then Intval (Den) = Intval (Right_Opnd (Num))
+               then
+                  Rewrite (Expression (N), Left_Opnd (Num));
+               end if;
+            end;
+         end if;
       end if;
    end Expand_Divide_Fixed_By_Fixed_Giving_Fixed;