public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* Re: [PR88579, patch] Calculating power of powers of two
       [not found] ` <e76675a7-a6d5-9963-7240-27fca0a84701@netcologne.de>
@ 2019-01-20 22:19   ` Harald Anlauf
  2019-01-20 22:22     ` Harald Anlauf
  2019-01-22 21:43     ` Thomas Koenig
  0 siblings, 2 replies; 3+ messages in thread
From: Harald Anlauf @ 2019-01-20 22:19 UTC (permalink / raw)
  To: gfortran; +Cc: Thomas Koenig, gcc-patches

[-- Attachment #1: Type: text/plain, Size: 1697 bytes --]

Dear all,

here's my revised patch for the treatment of (2**e) ** n and (- 2**e) **
n, trying to take into account the bitwidth of the result.

I've also extended the testcase to sample different integer kinds.

ChangeLogs see below.

Note: I don't have commit rights, so please somebody else take care
of it after review.

Thanks,
Harald

2019-01-20  Harald Anlauf  <anlauf@gmx.de>

	PR fortran/88579
	* trans-expr.c (gfc_conv_power_op): Handle cases of (2**e) ** integer
	and (- 2**e) ** integer.



2019-01-20  Harald Anlauf  <anlauf@gmx.de>

	PR fortran/88579
	* gfortran.dg/power_8.f90: New test.



On 01/19/19 16:45, Thomas Koenig wrote:
> Hi Harald,
> 
> 
>> now that my copyright assignment is on file, here's my first attempt
>> at a non-trivial patch.
> 
> Excellent :-)
> 
>> I have slightly rearranged Thomas' code, removed some, and added
>> generalizations for (2**e)**n and (-2**e)**n.  It works with the
>> testcase below.
> 
> That looks good.
> 
>> I'd like some feedback how to properly handle the case when
>> (-2**e) = -HUGE()-1, i.e. the number that falls outside the
>> symmetric range.  Should one skip that one?  Does anyone have
>> a template how to detect that case easily?  Regtesting otherwise
>> would fail for the last test (which most likely should be removed
>> later).
> 
> I think it is fine to fall back on the library version (which still
> exists) for that one.
> 
> The best way to check this is probably by getting the bit size
> of the expression by using something like
> 
>   ikind = gfc_validate_kind (BT_INTEGER, expr->ts.kind, false);
>   bit_size = gfc_integer_kinds[ikind].bit_size;
> 
> and take it from there.
> 
> Regards
> 
>     Thomas
> 
> 


[-- Attachment #2: pr88579.patch --]
[-- Type: text/x-patch, Size: 4511 bytes --]

Index: gcc/fortran/trans-expr.c
===================================================================
--- gcc/fortran/trans-expr.c	(revision 268106)
+++ gcc/fortran/trans-expr.c	(working copy)
@@ -3060,8 +3060,16 @@
       && TREE_CODE (TREE_TYPE (rse.expr)) == INTEGER_TYPE)
     {
       wi::tree_to_wide_ref wlhs = wi::to_wide (lse.expr);
-      HOST_WIDE_INT v;
+      HOST_WIDE_INT v, w;
+      int kind, ikind, bit_size;
+
       v = wlhs.to_shwi ();
+      w = abs (v);
+
+      kind = expr->value.op.op1->ts.kind;
+      ikind = gfc_validate_kind (BT_INTEGER, kind, false);
+      bit_size = gfc_integer_kinds[ikind].bit_size;
+
       if (v == 1)
 	{
 	  /* 1**something is always 1.  */
@@ -3068,11 +3076,28 @@
 	  se->expr = build_int_cst (TREE_TYPE (lse.expr), 1);
 	  return;
 	}
-      else if (v == 2 || v == 4 || v == 8 || v == 16)
+      else if (v == -1)
 	{
-	  /* 2**n = 1<<n, 4**n = 1<<(n+n), 8**n = 1 <<(3*n), 16**n =
-	   1<<(4*n), but we have to make sure to return zero if the
-	   number of bits is too large. */
+	  /* (-1)**n is 1 - ((n & 1) << 1) */
+	  tree type;
+	  tree tmp;
+
+	  type = TREE_TYPE (lse.expr);
+	  tmp = fold_build2_loc (input_location, BIT_AND_EXPR, type,
+				 rse.expr, build_int_cst (type, 1));
+	  tmp = fold_build2_loc (input_location, LSHIFT_EXPR, type,
+				 tmp, build_int_cst (type, 1));
+	  tmp = fold_build2_loc (input_location, MINUS_EXPR, type,
+				 build_int_cst (type, 1), tmp);
+	  se->expr = tmp;
+	  return;
+	}
+      else if (w > 0 && ((w & (w-1)) == 0) && ((w >> (bit_size-1)) == 0))
+	{
+	  /* Here v is +/- 2**e.  The further simplification uses
+	     2**n = 1<<n, 4**n = 1<<(n+n), 8**n = 1 <<(3*n), 16**n =
+	     1<<(4*n), etc., but we have to make sure to return zero
+	     if the number of bits is too large. */
 	  tree lshift;
 	  tree type;
 	  tree shift;
@@ -3080,27 +3105,25 @@
 	  tree cond;
 	  tree num_bits;
 	  tree cond2;
+	  tree tmp1;
 
 	  type = TREE_TYPE (lse.expr);
 
-	  if (v == 2)
+	  if (w == 2)
 	    shift = rse.expr;
-	  else if (v == 4)
+	  else if (w == 4)
 	    shift = fold_build2_loc (input_location, PLUS_EXPR,
 				     TREE_TYPE (rse.expr),
 				       rse.expr, rse.expr);
-	  else if (v == 8)
-	    shift = fold_build2_loc (input_location, MULT_EXPR,
-				     TREE_TYPE (rse.expr),
-				     build_int_cst (TREE_TYPE (rse.expr), 3),
-				     rse.expr);
-	  else if (v == 16)
-	    shift = fold_build2_loc (input_location, MULT_EXPR,
-				     TREE_TYPE (rse.expr),
-				     build_int_cst (TREE_TYPE (rse.expr), 4),
-				     rse.expr);
 	  else
-	    gcc_unreachable ();
+	    {
+	      /* use popcount for fast log2(w) */
+	      int e = wi::popcount (w-1);
+	      shift = fold_build2_loc (input_location, MULT_EXPR,
+				       TREE_TYPE (rse.expr),
+				       build_int_cst (TREE_TYPE (rse.expr), e),
+				       rse.expr);
+	    }
 
 	  lshift = fold_build2_loc (input_location, LSHIFT_EXPR, type,
 				    build_int_cst (type, 1), shift);
@@ -3111,26 +3134,27 @@
 	  num_bits = build_int_cst (TREE_TYPE (rse.expr), TYPE_PRECISION (type));
 	  cond2 = fold_build2_loc (input_location, GE_EXPR, logical_type_node,
 				   rse.expr, num_bits);
-	  se->expr = fold_build3_loc (input_location, COND_EXPR, type, cond2,
-				      build_int_cst (type, 0), cond);
+	  tmp1 = fold_build3_loc (input_location, COND_EXPR, type, cond2,
+				  build_int_cst (type, 0), cond);
+	  if (v > 0)
+	    {
+	      se->expr = tmp1;
+	    }
+	  else
+	    {
+	      /* for v < 0, calculate v**n = |v|**n * (-1)**n */
+	      tree tmp2;
+	      tmp2 = fold_build2_loc (input_location, BIT_AND_EXPR, type,
+				      rse.expr, build_int_cst (type, 1));
+	      tmp2 = fold_build2_loc (input_location, LSHIFT_EXPR, type,
+				      tmp2, build_int_cst (type, 1));
+	      tmp2 = fold_build2_loc (input_location, MINUS_EXPR, type,
+				      build_int_cst (type, 1), tmp2);
+	      se->expr = fold_build2_loc (input_location, MULT_EXPR, type,
+					  tmp1, tmp2);
+	    }
 	  return;
 	}
-      else if (v == -1)
-	{
-	  /* (-1)**n is 1 - ((n & 1) << 1) */
-	  tree type;
-	  tree tmp;
-
-	  type = TREE_TYPE (lse.expr);
-	  tmp = fold_build2_loc (input_location, BIT_AND_EXPR, type,
-				 rse.expr, build_int_cst (type, 1));
-	  tmp = fold_build2_loc (input_location, LSHIFT_EXPR, type,
-				 tmp, build_int_cst (type, 1));
-	  tmp = fold_build2_loc (input_location, MINUS_EXPR, type,
-				 build_int_cst (type, 1), tmp);
-	  se->expr = tmp;
-	  return;
-	}
     }
 
   gfc_int4_type_node = gfc_get_int_type (4);

[-- Attachment #3: pr88579.testcase --]
[-- Type: text/plain, Size: 1568 bytes --]

Index: gcc/testsuite/gfortran.dg/power_8.f90
===================================================================
--- gcc/testsuite/gfortran.dg/power_8.f90	(nonexistent)
+++ gcc/testsuite/gfortran.dg/power_8.f90	(working copy)
@@ -0,0 +1,64 @@
+! { dg-do run }
+! { dg-additional-options "-fdump-tree-original" }
+!
+! PR88579 - Test optimizations for bases that are powers of 2 or -2.
+program p
+  implicit none
+  integer(4) :: i, u
+  integer(1) :: j, v
+  integer(2) :: k, w
+  integer(8) :: z
+  ! Test selected positive bases
+  u = 1
+  do i=1,5
+     u = u * 64_4
+     if (u /= 64_4 ** i) stop 1
+  end do
+  z = 1
+  do i=1,7
+     z = z * 256_8
+     if (z /= 256_8 ** i) stop 2
+  end do
+  z = 1
+  do i=1,3
+     z = z * 65536_8
+     if (z /= 65536_8 ** i) stop 3
+  end do
+  ! Test selected negative bases and integer kind combinations
+  u = 1
+  do i=1,7
+     u = u * (-2_1)
+     if (u /= (-2_1) ** i) stop 4
+  end do
+  v = 1
+  do j=1,7
+     v = v * (-2_1)
+     if (v /= (-2_1) ** j) stop 5
+  end do
+  v = 1
+  do k=1,7
+     v = v * (-2_1)
+     if (v /= (-2_1) ** k) stop 6
+  end do
+  w = 1
+  do k=1,7
+     w = w * (-4_2)
+     if (w /= (-4_2) ** k) stop 7
+  end do
+  w = 1
+  do i=1,5
+     w = w * (-8_2)
+     if (w /= (-8_2) ** i) stop 8
+  end do
+  u = 1
+  do i=1,1
+     u = u * (-HUGE(1_4)/2-1)
+     if (u /= (-HUGE(1_4)/2-1) ** i) stop 9
+  end do
+  z = 1
+  do i=1,7
+     z = z * (-512_8)
+     if (z /= (-512_8) ** i) stop 10
+  end do
+end program p
+! { dg-final { scan-tree-dump-not "_gfortran_pow" "original" } }

^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: [PR88579, patch] Calculating power of powers of two
  2019-01-20 22:19   ` [PR88579, patch] Calculating power of powers of two Harald Anlauf
@ 2019-01-20 22:22     ` Harald Anlauf
  2019-01-22 21:43     ` Thomas Koenig
  1 sibling, 0 replies; 3+ messages in thread
From: Harald Anlauf @ 2019-01-20 22:22 UTC (permalink / raw)
  To: gfortran; +Cc: Thomas Koenig, gcc-patches

I was too anxious pressing the send button so that I forgot to mention:

Regtested with no new regressions on x86_64-pc-linux-gnu.

Sorry for that.

Harald

On 01/20/19 23:18, Harald Anlauf wrote:
> Dear all,
> 
> here's my revised patch for the treatment of (2**e) ** n and (- 2**e) **
> n, trying to take into account the bitwidth of the result.
> 
> I've also extended the testcase to sample different integer kinds.
> 
> ChangeLogs see below.
> 
> Note: I don't have commit rights, so please somebody else take care
> of it after review.
> 
> Thanks,
> Harald

^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: [PR88579, patch] Calculating power of powers of two
  2019-01-20 22:19   ` [PR88579, patch] Calculating power of powers of two Harald Anlauf
  2019-01-20 22:22     ` Harald Anlauf
@ 2019-01-22 21:43     ` Thomas Koenig
  1 sibling, 0 replies; 3+ messages in thread
From: Thomas Koenig @ 2019-01-22 21:43 UTC (permalink / raw)
  To: Harald Anlauf, gfortran; +Cc: gcc-patches

Hi Harald,

> here's my revised patch for the treatment of (2**e) ** n and (- 2**e) **
> n, trying to take into account the bitwidth of the result.
> 
> I've also extended the testcase to sample different integer kinds.
> 
> ChangeLogs see below.
> 
> Note: I don't have commit rights, so please somebody else take care
> of it after review.

Reviewed and committed as r268163.

Thanks a lot!

I see you already sent out a second patch.  We should probably see about
getting you commit rights soon, that should not be a problem.

Regards

	Thomas

^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2019-01-22 21:31 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
     [not found] <5C425499.8080809@gmx.de>
     [not found] ` <e76675a7-a6d5-9963-7240-27fca0a84701@netcologne.de>
2019-01-20 22:19   ` [PR88579, patch] Calculating power of powers of two Harald Anlauf
2019-01-20 22:22     ` Harald Anlauf
2019-01-22 21:43     ` Thomas Koenig

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).