> 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? 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
