On Wed, Jun 17, 2026 at 8:27 AM <[email protected]> wrote: > > From: Dhruv Chawla <[email protected]> > > This flag causes the frontend to emit annot_expr_parallel_kind for > do-concurrent loops, bypassing the PR83064 fix which would emit > annot_expr_ivdep_kind. This flag is meant to be a temporary fix, and > it along with patch 1 of this series recovers most of the performance gap > between flang and gfortran for SPEC2026 pot3d_s (speeding it up roughly > 5x), modulo libgomp performance issues. > > Bootstrapped and regtested on aarch64-linux-gnu.
We generally do not what to have user-facing flags that say "it might generate wrong-code". Instead we'd have asserting flags from the user, like -fdoconcurrent-are-parallelizable. But as the underlying issue is not visible to the user this doesn't work in this case. So please do not add such flag (flags need to be preserved forever). Iff you really agree that you want it, use a --parm instead that we can freely remove. But then, why not do this at the optimization phase of fortran and detect the problematic setup (temporaries it was, IIRC)? Or even, when you detect them, mark them as to be localized? Possibly both are not easily possible if there's function calls involved that might be inlined, exposing additional locals? > Signed-off-by: Dhruv Chawla <[email protected]> > > gcc/fortran/ChangeLog: > > PR fortran/125717 > * invoke.texi: Document the option. > * lang.opt: Add -fdoconcurrent-force-parallel. > * trans-stmt.cc (gfc_trans_forall_loop): Emit > annot_expr_parallel_kind when flag_doconcurrent_force_parallel > is set. > > gcc/testsuite/ChangeLog: > > * gfortran.dg/lto/do_concurrent_16_0.f90: New test. > --- > gcc/fortran/invoke.texi | 9 +++- > gcc/fortran/lang.opt | 4 ++ > gcc/fortran/trans-stmt.cc | 9 ++-- > .../gfortran.dg/lto/do_concurrent_16_0.f90 | 53 +++++++++++++++++++ > 4 files changed, 71 insertions(+), 4 deletions(-) > create mode 100644 gcc/testsuite/gfortran.dg/lto/do_concurrent_16_0.f90 > > diff --git a/gcc/fortran/invoke.texi b/gcc/fortran/invoke.texi > index 69c4fa69cc6..55a3fe3487b 100644 > --- a/gcc/fortran/invoke.texi > +++ b/gcc/fortran/invoke.texi > @@ -191,7 +191,8 @@ and warnings}. > -fbounds-check -ftail-call-workaround -ftail-call-workaround=@var{n} > -fcheck-array-temporaries > -fcheck=<all|array-temps|bits|bounds|do|mem|pointer|recursion> > --fcoarray=<none|single|shared|lib> -fexternal-blas -fexternal-blas64 -ff2c > +-fcoarray=<none|single|shared|lib> -fdoconcurrent-force-parallel > +-fexternal-blas -fexternal-blas64 -ff2c > -ffrontend-loop-interchange -ffrontend-optimize > -finit-character=@var{n} -finit-integer=@var{n} -finit-local-zero > -finit-derived -finit-logical=<true|false> > @@ -2070,6 +2071,12 @@ size and also compilation time may become excessive. > If that is the > case, it may be better to disable this option. Instances of packing > can be found by using @option{-Warray-temporaries}. > > +@opindex fdoconcurrent-force-parallel > +@item -fdoconcurrent-force-parallel > +This option forces parallelization of do-concurrent loops, bypassing the > +usual validity analysis done by the compiler. This can introduce correctness > +issues, so it should be used with caution. > + > @opindex fexternal-blas > @item -fexternal-blas > This option makes @command{gfortran} generate calls to BLAS functions > diff --git a/gcc/fortran/lang.opt b/gcc/fortran/lang.opt > index 6266d7f71bd..f90128a2cf3 100644 > --- a/gcc/fortran/lang.opt > +++ b/gcc/fortran/lang.opt > @@ -554,6 +554,10 @@ fdefault-real-16 > Fortran Var(flag_default_real_16) > Set the default real kind to an 16 byte wide type. > > +fdoconcurrent-force-parallel > +Fortran Var(flag_doconcurrent_force_parallel) > +Force auto-parallelization of do-concurrent loops. > + > fdollar-ok > Fortran Var(flag_dollar_ok) > Allow dollar signs in entity names. > diff --git a/gcc/fortran/trans-stmt.cc b/gcc/fortran/trans-stmt.cc > index 0b1a8fa6b14..b89a9347394 100644 > --- a/gcc/fortran/trans-stmt.cc > +++ b/gcc/fortran/trans-stmt.cc > @@ -4390,11 +4390,14 @@ gfc_trans_forall_loop (forall_info *forall_tmp, tree > body, > count, build_int_cst (TREE_TYPE (count), 0)); > > /* PR 83064 means that we cannot use annot_expr_parallel_kind until > - the autoparallelizer can handle this. */ > + the autoparallelizer can handle this. For now, use a flag to bypass > + the ivdep analysis for cases where the bug doesn't manifest itself. > */ > + annot_expr_kind kind = annot_expr_ivdep_kind; > + if (flag_doconcurrent_force_parallel && forall_tmp->do_concurrent) > + kind = annot_expr_parallel_kind; > if (forall_tmp->do_concurrent || iter->annot.ivdep) > cond = build3 (ANNOTATE_EXPR, TREE_TYPE (cond), cond, > - build_int_cst (integer_type_node, > - annot_expr_ivdep_kind), > + build_int_cst (integer_type_node, kind), > integer_zero_node); > > if (iter->annot.unroll && cond != error_mark_node) > diff --git a/gcc/testsuite/gfortran.dg/lto/do_concurrent_16_0.f90 > b/gcc/testsuite/gfortran.dg/lto/do_concurrent_16_0.f90 > new file mode 100644 > index 00000000000..7b0419854cd > --- /dev/null > +++ b/gcc/testsuite/gfortran.dg/lto/do_concurrent_16_0.f90 > @@ -0,0 +1,53 @@ > +! { dg-lto-do link } > +! { dg-require-effective-target pthread } > +! { dg-lto-options { { -O2 -flto -fdoconcurrent-force-parallel > -ftree-parallelize-loops=2 -fdump-tree-parloops2-details } } } > +! > +! Testcase taken from PR fortran/83064 > + > +program main > + use, intrinsic :: iso_fortran_env > + implicit none > + > + integer, parameter :: nsplit = 4 > + integer(int64), parameter :: ne = 100000 > + integer(int64) :: stride, low(nsplit), high(nsplit), edof(ne), i > + real(real64), dimension(nsplit) :: pi > + > + edof(1::4) = 1 > + edof(2::4) = 2 > + edof(3::4) = 3 > + edof(4::4) = 4 > + > + stride = ceiling(real(ne)/nsplit) > + do i = 1, nsplit > + high(i) = stride*i > + end do > + do i = 2, nsplit > + low(i) = high(i-1) + 1 > + end do > + low(1) = 1 > + high(nsplit) = ne > + > + pi = 0 > + do concurrent (i = 1:nsplit) > + pi(i) = sum(compute( low(i), high(i) )) > + end do > + print *, "PI", 4*sum(pi) > + > +contains > + > + pure function compute( low, high ) result( tmp ) > + integer(int64), intent(in) :: low, high > + real(real64), dimension(nsplit) :: tmp > + integer(int64) :: j, k > + > + tmp = 0 > + do j = low, high > + k = edof(j) > + tmp(k) = tmp(k) + (-1.0_real64)**(j+1) / real( 2*j-1 ) > + end do > + end function > + > +end program main > + > +! { dg-final { scan-ltrans-tree-dump "parallelizing \[^\n\r\]*loop" > "parloops2" } } > -- > 2.43.0 >
