On Wed, Jun 17, 2026 at 10:57 AM Dhruv Chawla <[email protected]> wrote:
>
> On 17/06/26 14:03, Kyrylo Tkachov 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.
> >>
>
> Hi Richi and Kyrill,
>
> > 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.
>
> That makes sense, I will respin this to be a --param instead. My
> apologies, that is effectively what I meant originally. This is just
> meant to be a temporary fix for autopar's issues.
> > 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?
>
> Yes, that is what it turned out to be - a caller-allocated stack array
> used as return storage for a callee (`compute` in the test case) got
> hoisted outside the loop (as its address was loop-invariant for a
> single thread), so multiple threads ended up writing to the same address
> thus leading to garbage output. This doesn't occur in the pot3d function,
> so it is safe to ignore this bug.

But it must be possible to classify a conservatively safe subset of
do concurrent loops from inside the frontend?  I'd really prefer that.

> Unfortunately I do not know how the auto-parallelizer exactly works so
> I had to ask an LLM to make me a patch that fixed it (which did
> actually work and seemed to pass the testsuite!), but I don't trust it
> enough to generally post as a patch. Thus the simple flag to bypass it.

autopar is essentially unmaintained ... but clearly the can_be_parallel
flag isn't correct for the IL as-is?  While I looked into autpar years
ago I don't remember much in what guarantees it makes, but I think
all of the safety is with the dependence analysis we skip with
can_be_parallel annotated loops.

> > 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?
>
> I initially thought it was similar to fast-math, but doing some digging
> exposed the actual bug in autopar.
>
> > 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
> >
> >
>
> --
> Regards,
> Dhruv

Reply via email to