https://gcc.gnu.org/bugzilla/show_bug.cgi?id=127812

            Bug ID: 127812
           Summary: [OpenMP] dispatch can generate calls to the wrong
                    function, calls with incorrect synchronization and
                    ICEs
           Product: gcc
           Version: 17.0
            Status: UNCONFIRMED
          Keywords: ice-on-valid-code, openmp, wrong-code
          Severity: normal
          Priority: P3
         Component: middle-end
          Assignee: unassigned at gcc dot gnu.org
          Reporter: gabravier at gmail dot com
  Target Milestone: ---

int v (int *);
#pragma omp declare variant (v) match (construct={dispatch})
int f (int *);
int a, b;

void
t1 (int *p)
{
  #pragma omp dispatch depend(in: a) novariants(1) depend(in: b)
  f (p);
}

void
t2 (int *p)
{
  #pragma omp dispatch nowait depend(inout: a)
  f (p);
}

My reading of the OpenMP standard is that these two functions should lower to
this:

void
t1 (int *p)
{
  GOMP_taskwait_depend({in: a, b});
  f (p);
}

void
t2 (int *p)
{
  GOMP_taskwait_depend({inout: a});
  v (p);
}

In particular, the use of novariants(1) forbids calling v (§15.6.2: “If
do-not-use-variant evaluates to true, no function variant is selected for the
function dispatch of the dispatch region associated with the novariants clause
even if one would be selected normally.”), and the nowait must not reach the
taskwait (§15.6: "If the dispatch directive specifies one or more depend
clauses, and after any variant substitution the depend properties of the
dispatch trait remain active in the OpenMP context of the function dispatch,
the behavior is as if those depend clauses are applied to an implicit taskwait
that is executed immediately before the call is executed. The construct
therefore implies the task-dependence scheduling constraint for the dependent
task that results from the implicit taskwait. The other dispatch-requirement
clauses have no effect on the execution of the dispatch construct apart from
the effect they may have on the arguments that are passed when calling a
function variant.").

Yet GCC (with -O2 -fopenmp) seems to have a different opinion:

"t1":
        push    rbx
        mov     rbx, rdi
        sub     rsp, 32
        movdqa  xmm0, XMMWORD PTR .LC0[rip]
        mov     rdi, rsp
        movaps  XMMWORD PTR [rsp], xmm0
        movq    xmm0, QWORD PTR .LC1[rip]
        movhps  xmm0, QWORD PTR .LC2[rip]
        movaps  XMMWORD PTR [rsp+16], xmm0
        call    "GOMP_taskwait_depend"
        add     rsp, 32
        mov     rdi, rbx
        pop     rbx
        jmp     "v"
"t2":
        push    rbx
        mov     eax, 1
        mov     rbx, rdi
        movq    xmm0, rax
        punpcklqdq      xmm0, xmm0
        sub     rsp, 32
        mov     rdi, rsp
        movaps  XMMWORD PTR [rsp], xmm0
        mov     QWORD PTR [rsp+16], OFFSET FLAT:"a"
        call    "GOMP_taskwait_depend_nowait"
        add     rsp, 32
        mov     rdi, rbx
        pop     rbx
        jmp     "v"
"b":
        .zero   4
"a":
        .zero   4
.LC0:
        .quad   2
        .quad   0
.LC1:
        .quad   "b"
.LC2:
        .quad   "a"

...which appears to be effectively doing:

void
t1 (int *p)
{
  GOMP_taskwait_depend ({in: a, b});
  v (p);               /* BUG: should be f (p); ?? */
}

void
t2 (int *p)
{
  GOMP_taskwait_depend_nowait ({inout: a});   /* should be GOMP_taskwait_depend
??? */
  v (p);
}

This reproduces on GCC trunk, 16 and 15. GCC 14 and before do not have dispatch
support.

>From reading the code that parses dispatch, it appears to me that
c_parser_omp_dispatch is incorrectly failing to copy/unlink the depend clauses.
My understanding of the OpenMP standard is that building an independent list
for them would fix this issue (note: I have not actually tested this). The C++
parser's cp_parser_omp_dispatch seems equivalently broken (the same testcase
has the same incorrect result there).

I have also attempted to translate the testcase to Fortran, for which my best
attempt was:

module m
  implicit none
  integer :: a, b
  interface
    subroutine v (p)
      integer :: p
    end subroutine
    subroutine f (p)
      integer :: p
    end subroutine
  end interface
  !$omp declare variant (f:v) match (construct={dispatch})
contains
  subroutine t1 (p)
    integer :: p
    !$omp dispatch depend(in: a) novariants(.true.) depend(in: b)
    call f (p)
  end subroutine

  subroutine t2 (p)
    integer :: p
    !$omp dispatch nowait depend(inout: a)
    call f (p)
  end subroutine
end module

...which actually straight up ICEs (on trunk, 16 and 15) with:

/app/example.f90:16:65:

   16 |     !$omp dispatch depend(in: a) novariants(.true.) depend(in: b)
      |                                                                 ^
internal compiler error: in gimplify_adjust_omp_clauses, at gimplify.cc:16474
0x295c598 diagnostics::context::diagnostic_impl(rich_location*,
diagnostics::metadata const*, diagnostics::option_id, char const*,
__va_list_tag (*) [1], diagnostics::kind)
        ???:0
0x29509cb internal_error(char const*, ...)
        ???:0
0xa96d18 fancy_abort(char const*, int, char const*)
        ???:0
0xf8dffc gimplify_expr(tree_node**, gimple**, gimple**, bool (*)(tree_node*),
int)
        ???:0
0xf9034a gimplify_stmt(tree_node**, gimple**)
        ???:0
0xf8d0db gimplify_expr(tree_node**, gimple**, gimple**, bool (*)(tree_node*),
int)
        ???:0
0xf9034a gimplify_stmt(tree_node**, gimple**)
        ???:0
0xf8d5b0 gimplify_expr(tree_node**, gimple**, gimple**, bool (*)(tree_node*),
int)
        ???:0
0xf99596 gimplify_body(tree_node*, bool)
        ???:0
0xf99a5c gimplify_function_tree(tree_node*)
        ???:0
0xd61bd7 cgraph_node::analyze()
        ???:0
0xd650a6 symbol_table::finalize_compilation_unit()
        ???:0
/cefs/73/73914a3840c0447f928fef27_gcc-trunk-20261010/bin/../libexec/gcc/x86_64-linux-gnu/17.0.0/f951
/app/example.f90 -quiet -dumpdir /app/ -dumpbase output.f90 -dumpbase-ext .f90
-masm=intel -mtune=generic -march=x86-64 -g -O2 -fdiagnostics-color=always
-fno-verbose-asm -fopenmp -o /app/output.s -fintrinsic-modules-path
/cefs/73/73914a3840c0447f928fef27_gcc-trunk-20261010/bin/../lib/gcc/x86_64-linux-gnu/17.0.0/finclude
-fpre-include=/usr/include/finclude/x86_64-linux-gnu/math-vector-fortran.h
Please submit a full bug report, with preprocessed source (by using
-freport-bug).
Please include the complete backtrace with any bug report.
See <https://gcc.gnu.org/bugs/> for instructions.

...for reasons somewhat less clear to me (gfc_trans_omp_dispatch certainly
seems quite suspect to me, in a similar way to the C and C++ parse functions
cited above), although it seems obvious too to me that this is rather quite a
bug.

Reply via email to