Patchwork [fortran] PR 57071, some power optimizations

login
register
mail settings
Submitter Thomas Koenig
Date April 28, 2013, 8:32 a.m.
Message ID <517CDE9C.2020301@netcologne.de>
Download mbox | patch
Permalink /patch/240240/
State New
Headers show

Comments

Thomas Koenig - April 28, 2013, 8:32 a.m.
Hello world,

the attached patch does some optimization on
power using ishft and iand, as discussed in the PR.

I have left out handling real numbers, that should be left
to the middle-end (PR 57073).

Regression-tested.  OK for trunk?

	Thomas

2013-04-28  Thomas Koenig  <tkoenig@gcc.gnu.org>

         PR fortran/57071
         * frontend-passes (optimize_power):  New function.
         (optimize_op):  Use it.

2013-04-28  Thomas Koenig  <tkoenig@gcc.gnu.org>

         PR fortran/57071
         * gfortran.dg/power_3.f90:  New test.
         * gfortran.dg/power_4.f90:  New test.
Tobias Burnus - April 28, 2013, 10:10 a.m.
Am 28.04.2013 10:32, schrieb Thomas Koenig:
> the attached patch does some optimization on
> power using ishft and iand, as discussed in the PR.
>
> I have left out handling real numbers, that should be left
> to the middle-end (PR 57073).
>
> Regression-tested.  OK for trunk?

OK - thanks for the patch.

I wonder whether one should also handle:
   1**k  == 1
That should only happen (in-real-world code) due to simplifying other 
expressions but it is simple to implement.

(0**k is also possible, but it gets more complicated: 0 for k > 0, 1 for 
k == 0 and invalid for k < 0 [which one might ignore]. As this is really 
special, one can also leave the library call.)

Tobias

> 2013-04-28 Thomas Koenig  <tkoenig@gcc.gnu.org>
>
>         PR fortran/57071
>         * frontend-passes (optimize_power):  New function.
>         (optimize_op):  Use it.
>
> 2013-04-28  Thomas Koenig  <tkoenig@gcc.gnu.org>
>
>         PR fortran/57071
>         * gfortran.dg/power_3.f90:  New test.
>         * gfortran.dg/power_4.f90:  New test.
Steve Kargl - April 28, 2013, 11:28 a.m.
On Sun, Apr 28, 2013 at 10:32:28AM +0200, Thomas Koenig wrote:
> Hello world,
> 
> the attached patch does some optimization on
> power using ishft and iand, as discussed in the PR.
> 
> I have left out handling real numbers, that should be left
> to the middle-end (PR 57073).
> 
> Regression-tested.  OK for trunk?
> 

% cat foo.f90
function foo(k)
   integer k
   integer foo
   foo = (1)**k
end function foo

% cat foo.f90.003t.original 
foo (integer(kind=4) & restrict k)
{
  integer(kind=4) __result_foo;

  __result_foo = _gfortran_pow_i4_i4 (1, *k);
  return __result_foo;
}

%  cat foo.f90.143t.optimized 

;; Function foo (foo_)

foo (integer(kind=4) & restrict k)
{
  integer(kind=4) __result_foo.0;
  integer(kind=4) D.1479;

<bb 2>:
  D.1479_2 = *k_1(D);
  __result_foo.0_3 = _gfortran_pow_i4_i4 (1, D.1479_2); [tail call]
  return __result_foo.0_3;

}

%  nm foo.o
         U _gfortran_pow_i4_i4
00000000 T foo_

:-)
Thomas Koenig - April 28, 2013, 1:39 p.m.
Am 28.04.2013 12:10, schrieb Tobias Burnus:
> OK - thanks for the patch.
>
> I wonder whether one should also handle:
>    1**k  == 1

Committed, thanks for the review!

I will do 1**k as a followup patch which should be quite obvious :-)

Regarding PR 57073, the real case - I have never worked with
GIMPLE, so I have no real idea how to start this.

Any volunteers?  Or should we handle this in the Fortran front
end after all?

	Thomas
Tobias Burnus - April 28, 2013, 6:12 p.m.
Thomas Koenig wrote:
> Regarding PR 57073, the real case - I have never worked with
> GIMPLE, so I have no real idea how to start this.
>
> Any volunteers?  Or should we handle this in the Fortran front
> end after all?

I think one should do it in the middle end. Actually, it shouldn't be 
that difficult. The starting point is gcc/builtins.c's fold_builtin_powi 
- all ingredients are there;  (1.0)**k, x**0, x**1 and x**(-1) are 
already handled. Thus, only (-1)**k is missing. For   "= (a)?(b):(c)" 
one uses "fold_build3_loc (loc, COND_EXPR, ..." and to check whether a 
real argument is -1, you can use "real_minus_onep".

How about writing your first middle end patch?

Tobias

Patch

Index: frontend-passes.c
===================================================================
--- frontend-passes.c	(Revision 198340)
+++ frontend-passes.c	(Arbeitskopie)
@@ -1091,7 +1091,66 @@  combine_array_constructor (gfc_expr *e)
   return true;
 }
 
+/* Change (-1)**k into 1-ishift(iand(k,1),1) and
+ 2**k into ishift(1,k) */
 
+static bool
+optimize_power (gfc_expr *e)
+{
+  gfc_expr *op1, *op2;
+  gfc_expr *iand, *ishft;
+
+  if (e->ts.type != BT_INTEGER)
+    return false;
+
+  op1 = e->value.op.op1;
+
+  if (op1 == NULL || op1->expr_type != EXPR_CONSTANT)
+    return false;
+
+  if (mpz_cmp_si (op1->value.integer, -1L) == 0)
+    {
+      gfc_free_expr (op1);
+
+      op2 = e->value.op.op2;
+
+      if (op2 == NULL)
+	return false;
+
+      iand = gfc_build_intrinsic_call (current_ns, GFC_ISYM_IAND,
+				       "_internal_iand", e->where, 2, op2,
+				       gfc_get_int_expr (e->ts.kind,
+							 &e->where, 1));
+				   
+      ishft = gfc_build_intrinsic_call (current_ns, GFC_ISYM_ISHFT,
+					"_internal_ishft", e->where, 2, iand,
+					gfc_get_int_expr (e->ts.kind,
+							  &e->where, 1));
+
+      e->value.op.op = INTRINSIC_MINUS;
+      e->value.op.op1 = gfc_get_int_expr (e->ts.kind, &e->where, 1);
+      e->value.op.op2 = ishft;
+      return true;
+    }
+  else if (mpz_cmp_si (op1->value.integer, 2L) == 0)
+    {
+      gfc_free_expr (op1);
+
+      op2 = e->value.op.op2;
+      if (op2 == NULL)
+	return false;
+
+      ishft = gfc_build_intrinsic_call (current_ns, GFC_ISYM_ISHFT,
+					"_internal_ishft", e->where, 2,
+					gfc_get_int_expr (e->ts.kind,
+							  &e->where, 1),
+					op2);
+      *e = *ishft;
+      return true;
+    }
+  return false;
+}
+
 /* Recursive optimization of operators.  */
 
 static bool
@@ -1152,6 +1211,10 @@  optimize_op (gfc_expr *e)
     case INTRINSIC_DIVIDE:
       return combine_array_constructor (e) || changed;
 
+    case INTRINSIC_POWER:
+      return optimize_power (e);
+      break;
+
     default:
       break;
     }