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

Reply via email to