https://gcc.gnu.org/g:5b0da09f0ed5da80734c143d3ce2bacd78dc0c28
commit r17-1734-g5b0da09f0ed5da80734c143d3ce2bacd78dc0c28 Author: Thomas Koenig <[email protected]> Date: Mon Jun 22 07:26:25 2026 +0200 Optimize (-1.0)**n to (real) (1 - ((n & 1) << 1)). 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. Diff: --- gcc/fortran/trans-expr.cc | 20 ++++++++ gcc/testsuite/gfortran.dg/power_10.f90 | 85 ++++++++++++++++++++++++++++++++++ gcc/testsuite/gfortran.dg/power_6.f90 | 2 - 3 files changed, 105 insertions(+), 2 deletions(-) diff --git a/gcc/fortran/trans-expr.cc b/gcc/fortran/trans-expr.cc index 00925f2ef5af..6e3661a09224 100644 --- a/gcc/fortran/trans-expr.cc +++ b/gcc/fortran/trans-expr.cc @@ -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 index 000000000000..f61b0f51b7eb --- /dev/null +++ b/gcc/testsuite/gfortran.dg/power_10.f90 @@ -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" } } diff --git a/gcc/testsuite/gfortran.dg/power_6.f90 b/gcc/testsuite/gfortran.dg/power_6.f90 index 7d3a1f412f38..4f504b7af75e 100644 --- a/gcc/testsuite/gfortran.dg/power_6.f90 +++ b/gcc/testsuite/gfortran.dg/power_6.f90 @@ -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" } }
