On Wed, Jun 17, 2026 at 10:33 AM Kyrylo Tkachov <[email protected]> wrote: > > > > > On 17 Jun 2026, at 10:22, Richard Biener <[email protected]> wrote: > > > > 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? > > Drive by comment from me, but is the "wrong-code” risk here non-deterministic > reassociation of FP operations? > So is this a fast-math-style wrong-code? Or does is it a more serious risk?
It's sharing a local variable among threads, aka "random" (timing wise) garbage. IMO much more severe than reproducible FP precision issues. Richard. > Thanks, > Kyrill > > > > >> 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 > >
