]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
Optimize (-1.0)**n to (real) (1 - ((n & 1) << 1)).
authorThomas Koenig <tkoenig@gcc.gnu.org>
Mon, 22 Jun 2026 05:26:25 +0000 (07:26 +0200)
committerThomas Koenig <tkoenig@gcc.gnu.org>
Mon, 22 Jun 2026 05:29:48 +0000 (07:29 +0200)
The problem was that the optimization done for PR 57073 uses powi and
friends, so it only applied to default integer exponent. The test
case has an integer(kind=8) exponent, which is is calculated by
calling a gfortran library function.

There are two possible approaches: One would be to convert all
integer types to default integer (because only the lowest-value
bit matters to the result) and call the right __builtin_powi function.
However, the generated code is suboptimal, see PR 125919.  I therefore
chose the variant which currently generates the best code.

This requires the change to the power_6.f90 test case.

gcc/fortran/ChangeLog:

PR fortran/125914
* trans-expr.cc (gfc_conv_power_op): Rewrite (-1.0)**n into
(real) (1 - ((n & 1) << 1)).

gcc/testsuite/ChangeLog:

PR fortran/125914
* gfortran.dg/power_6.f90: Remove scans for powi.
* gfortran.dg/power_10.f90: New test.

gcc/fortran/trans-expr.cc
gcc/testsuite/gfortran.dg/power_10.f90 [new file with mode: 0644]
gcc/testsuite/gfortran.dg/power_6.f90

index 00925f2ef5af9478369e40bd351ba18e1b3d2688..6e3661a092242a5cdaff02094006cbe25286ca8e 100644 (file)
@@ -4058,6 +4058,26 @@ gfc_conv_power_op (gfc_se * se, gfc_expr * expr)
 
        case BT_REAL:
          /* Use builtins for real ** int4.  */
+
+         if (real_minus_onep (lse.expr))
+           {
+             /* (-1.0)**n is (real) (1 - ((n & 1) << 1)), see the integer case
+                above.  */
+
+             tree lhs_type, rhs_type;
+             tree tmp;
+             lhs_type = TREE_TYPE (lse.expr);
+             rhs_type = TREE_TYPE (rse.expr);
+             tmp = fold_build2_loc (input_location, BIT_AND_EXPR, rhs_type,
+                                    rse.expr, build_int_cst (rhs_type, 1));
+             tmp = fold_build2_loc (input_location, LSHIFT_EXPR, rhs_type,
+                                    tmp, build_int_cst (rhs_type, 1));
+             tmp = fold_build2_loc (input_location, MINUS_EXPR, rhs_type,
+                                    build_int_cst (rhs_type, 1), tmp);
+             se->expr = fold_convert (lhs_type, tmp);
+             return;
+           }
+
          if (ikind == 0)
            {
              switch (kind)
diff --git a/gcc/testsuite/gfortran.dg/power_10.f90 b/gcc/testsuite/gfortran.dg/power_10.f90
new file mode 100644 (file)
index 0000000..f61b0f5
--- /dev/null
@@ -0,0 +1,85 @@
+! { dg-do run }
+! PR fortran/125914 - optimize 1.0*n
+! { dg-additional-options "-fdump-tree-original" }
+
+program memain
+  implicit none
+  integer, parameter :: n = 16
+  integer (kind=1), dimension(n) :: i1 
+  integer (kind=2), dimension(n) :: i2
+  integer (kind=4), dimension(n) :: i4 = &
+       [6, 5, 4, 4, 10, 8, 12, 8, 9, 4, 8, 11, 12, 10, 3, 12]
+  integer (kind=8), dimension(n) :: i8
+  real (kind=8), dimension(n) :: r8 = &
+       [0.996104819512799_8, 0.245675968329691_8, &
+       0.0303468106690589_8, 0.0240992716571487_8,  &
+       0.0354064316729468_8, 0.275774313901932_8, &
+       0.544792948166924_8, 0.445879110979491_8, &
+       0.241491365544482_8, 0.0954139664143259_8, &
+       0.0109187857324577_8, 0.0946393553679743_8, &
+       0.140308573675276_8, 0.353858089853078_8, &
+       0.879882896668272_8, 0.818438744841301_8] 
+
+  real (kind=4), dimension(n) :: r4
+
+  integer(kind=8) :: i
+  real (kind=8) :: s8
+  real (kind=4) :: s4
+
+  i1 = i4
+  i2 = i4
+  i8 = i4
+
+  s8 = 0
+  do i=1,n
+     s8 = s8 + r8(i)*(-1.0_8)**i1(i)
+  end do
+  if (abs (s8 - 2.3096522811663198_8) > 1e-13_8) stop 1
+
+  s8 = 0
+  do i=1,n
+     s8 = s8 + r8(i)*(-1.0_8)**i2(i)
+  end do
+  if (abs (s8 - 2.3096522811663198_8) > 1e-13_8) stop 2
+
+  s8 = 0
+  do i=1,n
+     s8 = s8 + r8(i)*(-1.0_8)**i4(i)
+  end do
+  if (abs (s8 - 2.3096522811663198_8) > 1e-13_8) stop 3
+
+  s8 = 0
+  do i=1,n
+     s8 = s8 + r8(i)*(-1.0_8)**i8(i)
+  end do
+  if (abs (s8 - 2.3096522811663198_8) > 1e-13_8) stop 4
+
+  r4 = r8
+
+  s4 = 0
+  do i=1,n
+     s4 = s4 + r4(i)*(-1.0)**i1(i)
+  end do
+  if (abs (s4 -  2.30965209) > 1e-5) stop 11
+
+  s4 = 0
+  do i=1,n
+     s4 = s4 + r4(i)*(-1.0)**i2(i)
+  end do
+  if (abs (s4 -  2.30965209) > 1e-5) stop 12
+
+  s4 = 0
+  do i=1,n
+     s4 = s4 + r4(i)*(-1.0)**i4(i)
+  end do
+  if (abs (s4 -  2.30965209) > 1e-5) stop 13
+
+  s4 = 0
+  do i=1,n
+     s4 = s4 + r4(i)*(-1.0)**i8(i)
+  end do
+  if (abs (s4 -  2.30965209) > 1e-5) stop 14
+
+end program memain
+! { dg-final { scan-tree-dump-not "_gfortran_pow" "original" } }
+! { dg-final { scan-tree-dump-not "__builtin_powi" "original" } }
index 7d3a1f412f38038054a52574cb87e08ebd36f1e8..4f504b7af75e7693e0d02cb1ebe44cd88047cf4e 100644 (file)
@@ -10,5 +10,3 @@ real function f(k)
 end
 
 ! { dg-final { scan-tree-dump-not "__builtin_powif"  "optimized" } }
-! { dg-final { scan-tree-dump "powi_cond_\[0-9\] = k_\[0-9\]\\(D\\) & 1;"  "optimized" } }
-! { dg-final { scan-tree-dump "powi_\[0-9\] = powi_cond_\[0-9\] \\? -1.0e\\+0 : 1.0e\\+0;"  "optimized" } }