https://gcc.gnu.org/g:9a06e4d6a117497c2536bf89bb6c7536289e44bb
commit 9a06e4d6a117497c2536bf89bb6c7536289e44bb Author: Sandra Loosemore <sloosem...@baylibre.com> Date: Wed Apr 30 17:46:31 2025 +0000 OpenMP: need_device_ptr and need_device_addr support for adjust_args This patch adds support for the "need_device_addr" modifier to the "adjust args" clause for the "declare variant" directive, and extends/re-works the support for "need_device_ptr" as well. This patch builds on waffl3x's recently posted patch, "OpenMP: C/C++ adjust-args numeric ranges", here. https://gcc.gnu.org/pipermail/gcc-patches/2025-April/681806.html In C++, "need_device_addr" supports mapping reference arguments to device pointers. In Fortran, it similarly supports arguments passed by reference, the default for the language, in contrast to "need_device_ptr" which is used to map arguments of c_ptr type. The C++ support is straightforward, but Fortran has some additional wrinkles involving arrays passed by descriptor (a new descriptor must be constructed with a pointer to the array data which is the only part mapped to the device), plus special cases for passing optional arguments and a whole array instead of a reference to its first element. gcc/cp/ChangeLog * parser.cc (cp_finish_omp_declare_variant): Adjust error messages. gcc/fortran/ChangeLog * trans-openmp.cc (gfc_trans_omp_declare_variant): Disallow polymorphic and optional arguments with need_device_addr for now, but don't reject need_device_addr entirely. gcc/ChangeLog * gimplify.cc (modify_call_for_omp_dispatch): Rework logic for need_device_ptr and need_device_addr adjustments. gcc/testsuite/Changelog * c-c++-common/gomp/adjust-args-10.c: Ignore the new sorry since the lack of proper diagnostic is already xfail'ed. * g++.dg/gomp/adjust-args-1.C: Adjust output patterns. * g++.dg/gomp/adjust-args-17.C: New. * gcc.dg/gomp/adjust-args-3.c: New. * gfortran.dg/gomp/adjust-args-14.f90: Don't expect this to fail now. libgomp/ChangeLog * libgomp.texi: Mark need_device_addr as supported. * testsuite/libgomp.c-c++-common/dispatch-3.c: New. * testsuite/libgomp.c++/need-device-ptr.C: New. * testsuite/libgomp.fortran/adjust-args-array-descriptor.f90: New. * testsuite/libgomp.fortran/need-device-ptr.f90: New. Co-Authored-By: Tobias Burnus <tbur...@baylibre.com> Diff: --- gcc/cp/parser.cc | 7 +- gcc/fortran/trans-openmp.cc | 44 ++++-- gcc/gimplify.cc | 88 +++++++++-- gcc/testsuite/c-c++-common/gomp/adjust-args-10.c | 2 + gcc/testsuite/g++.dg/gomp/adjust-args-1.C | 6 +- gcc/testsuite/g++.dg/gomp/adjust-args-17.C | 44 ++++++ gcc/testsuite/gcc.dg/gomp/adjust-args-3.c | 47 ++++++ gcc/testsuite/gfortran.dg/gomp/adjust-args-14.f90 | 2 +- libgomp/libgomp.texi | 1 + libgomp/testsuite/libgomp.c++/need-device-ptr.C | 175 +++++++++++++++++++++ .../testsuite/libgomp.c-c++-common/dispatch-3.c | 35 +++++ .../adjust-args-array-descriptor.f90 | 89 +++++++++++ .../testsuite/libgomp.fortran/need-device-ptr.f90 | 132 ++++++++++++++++ 13 files changed, 633 insertions(+), 39 deletions(-) diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc index 747209fc77f1..e60687f4a4e6 100644 --- a/gcc/cp/parser.cc +++ b/gcc/cp/parser.cc @@ -51407,7 +51407,8 @@ cp_finish_omp_declare_variant (cp_parser *parser, cp_token *pragma_tok, else { error_at (adjust_op_tok->location, - "expected %<nothing%> or %<need_device_ptr%>"); + "expected %<nothing%>, %<need_device_ptr%> or " + "%<need_device_addr%>"); /* We should be trying to recover here instead of immediately failing, skipping to close paren and continuing. */ goto fail; @@ -51418,8 +51419,8 @@ cp_finish_omp_declare_variant (cp_parser *parser, cp_token *pragma_tok, /* We should be trying to recover here instead of immediately failing, skipping to close paren and continuing. */ error_at (adjust_op_tok->location, - "expected %<nothing%> or %<need_device_ptr%> followed " - "by %<:%>"); + "expected %<nothing%>, %<need_device_ptr%> or " + "%<need_device_addr%> followed by %<:%>"); goto fail; } /* cp_parser_omp_var_list_no_open used to handle this, we don't use diff --git a/gcc/fortran/trans-openmp.cc b/gcc/fortran/trans-openmp.cc index 73ec9324dea1..b22bdfdf309e 100644 --- a/gcc/fortran/trans-openmp.cc +++ b/gcc/fortran/trans-openmp.cc @@ -11968,6 +11968,34 @@ gfc_trans_omp_declare_variant (gfc_namespace *ns, gfc_namespace *parent_ns) &arg->sym->declared_at, &loc); continue; } + if (arg_list->u.adj_args.need_addr + && arg->sym->ts.type == BT_CLASS) + { + // In OpenMP 6.1, mapping polymorphic variables + // is undefined behavior. 'sorry' would be an + // alternative or some other wording. + gfc_error ("Argument %qs at %L to list item in " + "%<need_device_addr%> at %L must not " + "be polymorphic", + arg->sym->name, + &arg->sym->declared_at, &loc); + continue; + } + if (arg_list->u.adj_args.need_addr + && arg->sym->attr.optional) + { + // OPTIONAL has the issue that we need to handle + // absent arguments on the caller side, which + // adds extra complications. + gfc_error ("Sorry, argument %qs at %L to list " + "item in %<need_device_addr%> at %L " + "with OPTIONAL argument is " + "not yet supported", + arg->sym->name, + &arg->sym->declared_at, &loc); + continue; + } + if (adjust_args_list.contains (arg->sym)) { gfc_error ("%qs at %L is specified more than " @@ -11976,22 +12004,6 @@ gfc_trans_omp_declare_variant (gfc_namespace *ns, gfc_namespace *parent_ns) } adjust_args_list.safe_push (arg->sym); - if (arg_list->u.adj_args.need_addr) - { - /* TODO: Has to to support OPTIONAL and array - descriptors; should check for CLASS, coarrays? - Reject "abc" and 123 as actual arguments (in - gimplify.cc or in the FE? Reject noncontiguous - actuals? Cf. also PR C++/118859. - Also check array-valued type(c_ptr). */ - static bool warned = false; - if (!warned) - sorry_at (gfc_get_location (&loc), - "%<need_device_addr%> not yet " - "supported"); - warned = true; - continue; - } if (arg_list->u.adj_args.need_ptr || arg_list->u.adj_args.need_addr) { diff --git a/gcc/gimplify.cc b/gcc/gimplify.cc index 5ebfc184b3ea..9bd78b9f2eea 100644 --- a/gcc/gimplify.cc +++ b/gcc/gimplify.cc @@ -4434,25 +4434,81 @@ modify_call_for_omp_dispatch (tree expr, tree dispatch_clauses, // device_num) // but arg has to be the actual pointer, not a // reference or a conversion expression. - tree actual_ptr = TREE_CODE (arg) == ADDR_EXPR ? TREE_OPERAND (arg, 0) - : arg; - if (TREE_CODE (actual_ptr) == NOP_EXPR - && (TREE_CODE (TREE_TYPE (TREE_OPERAND (actual_ptr, 0))) - == REFERENCE_TYPE)) - { - actual_ptr = TREE_OPERAND (actual_ptr, 0); - actual_ptr - = build1 (INDIRECT_REF, TREE_TYPE (actual_ptr), actual_ptr); - } tree fn = builtin_decl_explicit (BUILT_IN_OMP_GET_MAPPED_PTR); - tree mapped_arg - = build_call_expr_loc (loc, fn, 2, actual_ptr, dispatch_device_num); + tree mapped_arg = NULL_TREE; + bool reference_to_ptr_p = false; + + tree argtype = TREE_TYPE (arg); + if (!POINTER_TYPE_P (argtype)) + { + sorry_at (EXPR_LOCATION (arg), + "Invalid non-pointer/reference argument " + "not diagnosed properly earlier"); + return arg; + } + + /* Fortran C_PTR passed by reference? Also handle the weird case + where an array of C_PTR is passed instead of its first element. */ + if (need_device_ptr + && lang_GNU_Fortran () + && (POINTER_TYPE_P (TREE_TYPE (argtype)) + || (TREE_CODE (TREE_TYPE (argtype)) == ARRAY_TYPE + && POINTER_TYPE_P (TREE_TYPE (TREE_TYPE (argtype)))))) + reference_to_ptr_p = true; + + /* C++ pointer passed by reference? */ + else if (need_device_ptr + && TREE_CODE (argtype) == REFERENCE_TYPE + && TREE_CODE (TREE_TYPE (argtype)) == POINTER_TYPE) + reference_to_ptr_p = true; + + /* If reference_to_ptr_p is true, we need to dereference arg to + get the actual pointer. */ + tree actual_ptr = (reference_to_ptr_p + ? build_fold_indirect_ref (arg) : arg); + tree actual_ptr_type = TREE_TYPE (actual_ptr); + STRIP_NOPS (actual_ptr); + + if (lang_hooks.decls.omp_array_data (actual_ptr, true)) + { + /* This is a Fortran array with a descriptor. The actual_ptr that + lives on the target is the array data, not the descriptor. */ + tree array_data + = lang_hooks.decls.omp_array_data (actual_ptr, false); + tree mapped_array_data = + build_call_expr_loc (loc, fn, 2, array_data, dispatch_device_num); + + gcc_assert (TREE_CODE (array_data) == COMPONENT_REF); + + /* We need to create a new array descriptor newd that points at the + mapped actual_ptr instead of the original one. Start by + creating the new descriptor and copy-initializing it from the + existing one. */ + tree oldd = TREE_OPERAND (array_data, 0); + tree newd = create_tmp_var (TREE_TYPE (oldd), get_name (oldd)); + tree t2 = build2 (MODIFY_EXPR, void_type_node, newd, oldd); + if (init_code) + init_code = build2 (COMPOUND_EXPR, void_type_node, init_code, t2); + else + init_code = t2; + + /* Now stash the mapped array pointer in the new descriptor newd. */ + tree lhs = build3 (COMPONENT_REF, TREE_TYPE (array_data), newd, + TREE_OPERAND (array_data, 1), + TREE_OPERAND (array_data, 2)); + t2 = build2 (MODIFY_EXPR, void_type_node, lhs, mapped_array_data); + init_code = build2 (COMPOUND_EXPR, void_type_node, init_code, t2); + mapped_arg = build_fold_addr_expr (newd); + } + else + mapped_arg + = build_call_expr_loc (loc, fn, 2, actual_ptr, dispatch_device_num); - if (TREE_CODE (arg) == ADDR_EXPR - || (TREE_CODE (TREE_TYPE (actual_ptr)) == REFERENCE_TYPE)) + /* Cast mapped_arg back to its original type, and if we need a + reference, build one. */ + mapped_arg = build1 (NOP_EXPR, actual_ptr_type, mapped_arg); + if (reference_to_ptr_p) mapped_arg = build_fold_addr_expr (mapped_arg); - else if (TREE_CODE (arg) == NOP_EXPR) - mapped_arg = build1 (NOP_EXPR, TREE_TYPE (arg), mapped_arg); return mapped_arg; }; diff --git a/gcc/testsuite/c-c++-common/gomp/adjust-args-10.c b/gcc/testsuite/c-c++-common/gomp/adjust-args-10.c index 5cda21e07eee..6730dfeba2de 100644 --- a/gcc/testsuite/c-c++-common/gomp/adjust-args-10.c +++ b/gcc/testsuite/c-c++-common/gomp/adjust-args-10.c @@ -11,3 +11,5 @@ void f0(int *p0, int *p1, int *p2, int *p3, int *p4) #pragma omp dispatch b0(p0, p1, p2, p3, p4, 42); /* { dg-error "variadic argument 5 specified in an 'append_args' clause with the 'need_device_ptr' modifier must be of pointer type" "" { xfail *-*-* } } */ } + +/* { dg-prune-output "sorry, unimplemented: Invalid non-pointer/reference argument not diagnosed properly earlier" } */ diff --git a/gcc/testsuite/g++.dg/gomp/adjust-args-1.C b/gcc/testsuite/g++.dg/gomp/adjust-args-1.C index 3aee78e3bb37..d0e0bce7444d 100644 --- a/gcc/testsuite/g++.dg/gomp/adjust-args-1.C +++ b/gcc/testsuite/g++.dg/gomp/adjust-args-1.C @@ -13,13 +13,13 @@ int f2a (void *a); int f2b (void *a); #pragma omp declare variant (f0) match (construct={dispatch},device={arch(gcn)}) adjust_args (need_device_ptr: a) /* { dg-error "'int f0.void..' used as a variant with incompatible 'construct' selector sets" } */ int f2c (void *a); -#pragma omp declare variant (f1) match (construct={dispatch}) adjust_args (other: a) /* { dg-error "expected 'nothing' or 'need_device_ptr'" } */ +#pragma omp declare variant (f1) match (construct={dispatch}) adjust_args (other: a) /* { dg-error "expected 'nothing', 'need_device_ptr' or 'need_device_addr'" } */ int f3 (int a); #pragma omp declare variant (f0) adjust_args (nothing: a) /* { dg-error "an 'adjust_args' clause requires a 'match' clause" } */ int f4 (void *a); -#pragma omp declare variant (f1) match (construct={dispatch}) adjust_args () /* { dg-error "expected 'nothing' or 'need_device_ptr' followed by ':'" } */ +#pragma omp declare variant (f1) match (construct={dispatch}) adjust_args () /* { dg-error "expected 'nothing', 'need_device_ptr' or 'need_device_addr' followed by ':'" } */ int f5 (int a); -#pragma omp declare variant (f1) match (construct={dispatch}) adjust_args (nothing) /* { dg-error "expected 'nothing' or 'need_device_ptr' followed by ':'" } */ +#pragma omp declare variant (f1) match (construct={dispatch}) adjust_args (nothing) /* { dg-error "expected 'nothing', 'need_device_ptr' or 'need_device_addr' followed by ':'" } */ int f6 (int a); #pragma omp declare variant (f1) match (construct={dispatch}) adjust_args (nothing:) /* { dg-error "expected primary-expression before '\\)' token" } */ int f7 (int a); diff --git a/gcc/testsuite/g++.dg/gomp/adjust-args-17.C b/gcc/testsuite/g++.dg/gomp/adjust-args-17.C new file mode 100644 index 000000000000..62ddab0b74bb --- /dev/null +++ b/gcc/testsuite/g++.dg/gomp/adjust-args-17.C @@ -0,0 +1,44 @@ +void f(int*,int &,int*); +void f0(int*,int &,int*); +void f1(int*,int &,int*); +void f2(int*,int &,int*); +void f3(int*,int &,int*); +void f4(int*,int &,int*); +void f5(int*,int &,int*); +void f6(int*,int &,int*); +void f7(int*,int &,int*); +void f8(int*,int &,int*); +void f9(int*,int &,int*); +void fa(int*,int &,int*); +void f10(int*,int &,int*); +void f11(int*,int &,int*); +void f12(int*,int &,int*); +void f13(int*,int &,int*); +void f14(int*,int &,int*); +void f15(int*,int &,int*); +void f16(int*,int &,int*); + +#pragma omp declare variant(f) match(construct={dispatch}) adjust_args(x : y) // { dg-error "expected 'nothing', 'need_device_ptr' or 'need_device_addr'" } +#pragma omp declare variant(f0) match(construct={dispatch}) adjust_args(x) // { dg-error "expected 'nothing', 'need_device_ptr' or 'need_device_addr' followed by ':'" } +#pragma omp declare variant(f1) match(construct={dispatch}) adjust_args(x,) // { dg-error "expected 'nothing', 'need_device_ptr' or 'need_device_addr' followed by ':'" } +#pragma omp declare variant(f2) match(construct={dispatch}) adjust_args(foo x) // { dg-error "expected 'nothing', 'need_device_ptr' or 'need_device_addr' followed by ':'" } +#pragma omp declare variant(f3) match(construct={dispatch}) adjust_args(nothing) // { dg-error "expected 'nothing', 'need_device_ptr' or 'need_device_addr' followed by ':'" } +#pragma omp declare variant(f4) match(construct={dispatch}) adjust_args(need_device_ptr) // { dg-error "expected 'nothing', 'need_device_ptr' or 'need_device_addr' followed by ':'" } +#pragma omp declare variant(f5) match(construct={dispatch}) adjust_args(nothing x) // { dg-error "expected 'nothing', 'need_device_ptr' or 'need_device_addr' followed by ':'" } +#pragma omp declare variant(f6) match(construct={dispatch}) adjust_args(need_device_ptr x) // { dg-error "expected 'nothing', 'need_device_ptr' or 'need_device_addr' followed by ':'" } +#pragma omp declare variant(f7) match(construct={dispatch}) adjust_args(need_device_addr x) // { dg-error "expected 'nothing', 'need_device_ptr' or 'need_device_addr' followed by ':'" } +#pragma omp declare variant(f8) match(construct={dispatch}) adjust_args(nothing :) // { dg-error "expected primary-expression before '\\)' token" } +#pragma omp declare variant(f9) match(construct={dispatch}) adjust_args(need_device_ptr :) // { dg-error "expected primary-expression before '\\)' token" } +#pragma omp declare variant(fa) match(construct={dispatch}) adjust_args(need_device_addr :) // { dg-error "expected primary-expression before '\\)' token" } +#pragma omp declare variant(f10) match(construct={dispatch}) adjust_args(need_device_addr : omp_num_args-1) // { dg-error "expected ':' before '\\)' token" } +// { dg-note "93: an expression is only allowed in a numeric range" "" { target *-*-* } .-1 } + +// Valid: +#pragma omp declare variant(f11) match(construct={dispatch}) adjust_args(nothing : z, 1:2) +#pragma omp declare variant(f12) match(construct={dispatch}) adjust_args(need_device_ptr : x) +#pragma omp declare variant(f13) match(construct={dispatch}) adjust_args(need_device_addr : y) +#pragma omp declare variant(f14) match(construct={dispatch}) adjust_args(nothing : :) +#pragma omp declare variant(f15) match(construct={dispatch}) adjust_args(need_device_ptr : 3:3) +#pragma omp declare variant(f16) match(construct={dispatch}) adjust_args(need_device_addr : 2:2) + +void g(int*x, int &y, int *z); diff --git a/gcc/testsuite/gcc.dg/gomp/adjust-args-3.c b/gcc/testsuite/gcc.dg/gomp/adjust-args-3.c new file mode 100644 index 000000000000..a9e7fabab2b3 --- /dev/null +++ b/gcc/testsuite/gcc.dg/gomp/adjust-args-3.c @@ -0,0 +1,47 @@ +void f(int*,int *,int*); +void f0(int*,int *,int*); +void f1(int*,int *,int*); +void f2(int*,int *,int*); +void f3(int*,int *,int*); +void f4(int*,int *,int*); +void f5(int*,int *,int*); +void f6(int*,int *,int*); +void f7(int*,int *,int*); +void f8(int*,int *,int*); +void f9(int*,int *,int*); +void fa(int*,int *,int*); +void f10(int*,int *,int*); +void f11(int*,int *,int*); +void f12(int*,int *,int*); +void f13(int*,int *,int*); +void f14(int*,int *,int*); +void f15(int*,int *,int*); +void f16(int*,int *,int*); + +#pragma omp declare variant(f) match(construct={dispatch}) adjust_args(x : y) // { dg-error "expected 'nothing' or 'need_device_ptr'" } +#pragma omp declare variant(f0) match(construct={dispatch}) adjust_args(x) // { dg-error "expected 'nothing' or 'need_device_ptr' followed by ':'" } +#pragma omp declare variant(f1) match(construct={dispatch}) adjust_args(x,) // { dg-error "expected 'nothing' or 'need_device_ptr' followed by ':'" } +#pragma omp declare variant(f2) match(construct={dispatch}) adjust_args(foo x) // { dg-error "expected 'nothing' or 'need_device_ptr' followed by ':'" } +#pragma omp declare variant(f3) match(construct={dispatch}) adjust_args(nothing) // { dg-error "expected 'nothing' or 'need_device_ptr' followed by ':'" } +#pragma omp declare variant(f4) match(construct={dispatch}) adjust_args(need_device_ptr) // { dg-error "expected 'nothing' or 'need_device_ptr' followed by ':'" } +#pragma omp declare variant(f5) match(construct={dispatch}) adjust_args(nothing x) // { dg-error "expected 'nothing' or 'need_device_ptr' followed by ':'" } +#pragma omp declare variant(f6) match(construct={dispatch}) adjust_args(need_device_ptr x) // { dg-error "expected 'nothing' or 'need_device_ptr' followed by ':'" } +#pragma omp declare variant(f7) match(construct={dispatch}) adjust_args(need_device_addr x) // { dg-error "expected 'nothing' or 'need_device_ptr'" } +#pragma omp declare variant(f8) match(construct={dispatch}) adjust_args(nothing :) // { dg-error "expected expression before '\\)' token" } +#pragma omp declare variant(f9) match(construct={dispatch}) adjust_args(need_device_ptr :) // { dg-error "expected expression before '\\)' token" } +#pragma omp declare variant(fa) match(construct={dispatch}) adjust_args(need_device_addr :) // { dg-error "expected 'nothing' or 'need_device_ptr'" } +// { dg-note "73: 'need_device_addr' is not valid for C" "" { target *-*-* } .-1 } +#pragma omp declare variant(f10) match(construct={dispatch}) adjust_args(need_device_ptr : omp_num_args-1) // { dg-error "expected ':' before '\\)' token" } +// { dg-note "92: an expression is only allowed in a numeric range" "" { target *-*-* } .-1 } + +// Valid: +#pragma omp declare variant(f11) match(construct={dispatch}) adjust_args(nothing : z, 1:2) +#pragma omp declare variant(f12) match(construct={dispatch}) adjust_args(need_device_ptr : x) +#pragma omp declare variant(f13) match(construct={dispatch}) adjust_args(need_device_addr : y) // { dg-error "expected 'nothing' or 'need_device_ptr'" } +// { dg-note "74: 'need_device_addr' is not valid for C" "" { target *-*-* } .-1 } +#pragma omp declare variant(f14) match(construct={dispatch}) adjust_args(nothing : :) +#pragma omp declare variant(f15) match(construct={dispatch}) adjust_args(need_device_ptr : 3:3) +#pragma omp declare variant(f16) match(construct={dispatch}) adjust_args(need_device_addr : 2:2)// { dg-error "expected 'nothing' or 'need_device_ptr'" } +// { dg-note "74: 'need_device_addr' is not valid for C" "" { target *-*-* } .-1 } + +void g(int*x, int *y, int *z); diff --git a/gcc/testsuite/gfortran.dg/gomp/adjust-args-14.f90 b/gcc/testsuite/gfortran.dg/gomp/adjust-args-14.f90 index 313e4e65f9f2..ed2881e1f078 100644 --- a/gcc/testsuite/gfortran.dg/gomp/adjust-args-14.f90 +++ b/gcc/testsuite/gfortran.dg/gomp/adjust-args-14.f90 @@ -14,7 +14,7 @@ contains ! { dg-error "19: Argument 'y' at .1. to list item in 'need_device_addr' at .2. must not have the VALUE attribute" "" { target *-*-* } 8 } ! { dg-error "64: Argument 'y' at .1. to list item in 'need_device_addr' at .2. must not have the VALUE attribute" "" { target *-*-* } 9 } -! { dg-message "sorry, unimplemented: 'need_device_addr' not yet supported" "" { target *-*-* } 9 } + ! { dg-error "Argument 'z' at .1. to list item in 'need_device_ptr' at .2. must be a scalar of TYPE\\(C_PTR\\)" "" { target *-*-* } 8 } ! { dg-error "Argument 'z' at .1. to list item in 'need_device_ptr' at .2. must be a scalar of TYPE\\(C_PTR\\)" "" { target *-*-* } 10 } diff --git a/libgomp/libgomp.texi b/libgomp/libgomp.texi index 32d651498afa..9a9acec571ce 100644 --- a/libgomp/libgomp.texi +++ b/libgomp/libgomp.texi @@ -516,6 +516,7 @@ Technical Report (TR) 12 is the second preview for OpenMP 6.0. @item Extension of @code{interop} operation of @code{append_args}, allowing all modifiers of the @code{init} clause @tab N @tab +@item New @code{need_device_addr} modifier to @code{adjust_args} clause @tab Y @tab @item @code{interop} clause to @code{dispatch} @tab Y @tab @item @code{message} and @code{severity} clauses to @code{parallel} directive @tab N @tab diff --git a/libgomp/testsuite/libgomp.c++/need-device-ptr.C b/libgomp/testsuite/libgomp.c++/need-device-ptr.C new file mode 100644 index 000000000000..d7babffae966 --- /dev/null +++ b/libgomp/testsuite/libgomp.c++/need-device-ptr.C @@ -0,0 +1,175 @@ +// Test the need_device_ptr and need_device_addr modifiers to the adjust_args clause + +#include <omp.h> + +void fptr_var (int *x1, int *x2, int *x3, int **x3a, int *x4, int *x5, int *x6, int **x6a) +{ + #pragma omp target is_device_ptr (x1) + { if (*x1 != 1) __builtin_abort (); *x1 *= -1; } + + #pragma omp target is_device_ptr (x2) + { if (*x2 != 2) __builtin_abort (); *x2 *= -1; } + + #pragma omp target is_device_ptr (x3) + { if (*x3 != 3) __builtin_abort (); *x3 *= -1; } + + #pragma omp target is_device_ptr (x3a) + { if (**x3a != 30) __builtin_abort (); **x3a *= -1; } + + #pragma omp target is_device_ptr (x4) + { if (*x4 != 4) __builtin_abort (); *x4 *= -1; } + + #pragma omp target is_device_ptr (x5) + { if (*x5 != 5) __builtin_abort (); *x5 *= -1; } + + #pragma omp target is_device_ptr (x6) + { if (*x6 != 6) __builtin_abort (); *x6 *= -1; } + + #pragma omp target is_device_ptr (x6a) + { if (**x6a != 60) __builtin_abort (); **x6a *= -1; } +} + +#pragma omp declare variant(fptr_var) match(construct={dispatch}) adjust_args (need_device_ptr : 1:8) +void fptr (int *x1, int *x2, int *x3, int **x3a, int *x4, int *x5, int *x6, int **x6a); + +void faddr_var (int &x1, int &x2, int &x3, int *&x3a, int &x4, int &x5, int &x6, int *&x6a) +{ + #pragma omp target has_device_addr (x1) + { if (x1 != 1) __builtin_abort (); x1 *= -1; } + + #pragma omp target has_device_addr (x2) + { if (x2 != 2) __builtin_abort (); x2 *= -1; } + + #pragma omp target has_device_addr (x3) + { if (x3 != 3) __builtin_abort (); x3 *= -1; } + + #pragma omp target has_device_addr (x3a) + { if (*x3a != 30) __builtin_abort (); *x3a *= -1; } + + #pragma omp target has_device_addr (x4) + { if (x4 != 4) __builtin_abort (); x4 *= -1; } + + #pragma omp target has_device_addr (x5) + { if (x5 != 5) __builtin_abort (); x5 *= -1; } + + #pragma omp target has_device_addr (x6) + { if (x6 != 6) __builtin_abort (); x6 *= -1; } + + #pragma omp target has_device_addr (x6a) + { if (*x6a != 60) __builtin_abort (); *x6a *= -1; } +} + +#pragma omp declare variant(faddr_var) match(construct={dispatch}) adjust_args (need_device_addr : 1:8) +void faddr (int &x1, int &x2, int &x3, int *&, int &x4, int &x5, int &x6, int *&); + +void caller_ptr(int x, int &y, int *z, int *zptr) +{ + int a = 4; + int bval = 5; + int &b = bval; + int *c = (int*) __builtin_malloc (sizeof (int)); + int *cptr; + *c = 6; + + zptr = (int *) omp_target_alloc (sizeof (int), omp_get_default_device ()); + cptr = (int *) omp_target_alloc (sizeof (int), omp_get_default_device ()); + + #pragma omp target is_device_ptr(cptr, zptr) + { + *zptr = 30; + *cptr = 60; + } + + #pragma omp target enter data map(x, a, b, c[:1], cptr, zptr) + + #pragma omp dispatch + fptr (&x, &y, z, &zptr, &a, &b, c, &cptr); + + #pragma omp target exit data map(x, a, b, c[:1], cptr, zptr) + #pragma omp target update from(y, z[:1]) + + if (x != -1) __builtin_abort (); + if (y != -2) __builtin_abort (); + if (*z != -3) __builtin_abort (); + + if (a != -4) __builtin_abort (); + if (b != -5) __builtin_abort (); + if (*c != -6) __builtin_abort (); + + #pragma omp target is_device_ptr(cptr, zptr) + { + if (*zptr != -30) __builtin_abort (); + if (*cptr != -60) __builtin_abort (); + } + + __builtin_free (c); + omp_target_free (cptr, omp_get_default_device ()); + omp_target_free (zptr, omp_get_default_device ()); +} + +void caller_addr(int x, int &y, int *z, int *zptr) +{ + int a = 4; + int bval = 5; + int &b = bval; + int *c = (int*) __builtin_malloc (sizeof (int)); + int *cptr; + *c = 6; + + zptr = (int *) omp_target_alloc (sizeof (int), omp_get_default_device ()); + cptr = (int *) omp_target_alloc (sizeof (int), omp_get_default_device ()); + + #pragma omp target is_device_ptr(cptr, zptr) + { + *zptr = 30; + *cptr = 60; + } + + #pragma omp target enter data map(x, a, b, c[:1], cptr, zptr) + + #pragma omp dispatch + faddr (x, y, *z, zptr, a, b, *c, cptr); + + #pragma omp target exit data map(x, a, b, c[:1], cptr, zptr) + #pragma omp target update from(y, z[:1]) + + if (x != -1) __builtin_abort (); + if (y != -2) __builtin_abort (); + if (*z != -3) __builtin_abort (); + + if (a != -4) __builtin_abort (); + if (b != -5) __builtin_abort (); + if (*c != -6) __builtin_abort (); + + #pragma omp target is_device_ptr(cptr, zptr) + { + if (*zptr != -30) __builtin_abort (); + if (*cptr != -60) __builtin_abort (); + } + + + __builtin_free (c); +} + +int +main () +{ + int x = 1; + int yval = 2; + int &y = yval; + int *z = (int *) __builtin_malloc (sizeof (int)); + int *zptr; + *z = 3; + + #pragma omp target data map(y, z[:1]) + caller_ptr (x, y, z, zptr); + + x = 1; + y = 2; + *z = 3; + + #pragma omp target data map(y, z[:1], zptr) + caller_addr (x, y, z, zptr); + + __builtin_free (z); +} diff --git a/libgomp/testsuite/libgomp.c-c++-common/dispatch-3.c b/libgomp/testsuite/libgomp.c-c++-common/dispatch-3.c new file mode 100644 index 000000000000..2c41e3cd470b --- /dev/null +++ b/libgomp/testsuite/libgomp.c-c++-common/dispatch-3.c @@ -0,0 +1,35 @@ +/* { dg-additional-options "-fdump-tree-gimple" } */ + +/* PR c++/118859 */ + +void f_var(int *y) { + #pragma omp target is_device_ptr(y) + { + if (*y != 5) + __builtin_abort (); + *y += 10; + } +} +#pragma omp declare variant(f_var) match(construct={dispatch}) adjust_args(need_device_ptr : 1) +void f(int *); + +static void test() +{ + int x = 5; + #pragma omp target enter data map(x) + + #pragma omp dispatch + f(&x); + + #pragma omp target exit data map(x) + if (x != 15) + __builtin_abort (); +} + +int main() +{ + test(); +} + +// { dg-final { scan-tree-dump "D\\.\[0-9\]+ = __builtin_omp_get_mapped_ptr \\(&x, D\\.\[0-9\]+\\);" "gimple" } } +// { dg-final { scan-tree-dump "f_var \\(D\\.\[0-9\]+\\);" "gimple" } } diff --git a/libgomp/testsuite/libgomp.fortran/adjust-args-array-descriptor.f90 b/libgomp/testsuite/libgomp.fortran/adjust-args-array-descriptor.f90 new file mode 100644 index 000000000000..dd9b57b8387f --- /dev/null +++ b/libgomp/testsuite/libgomp.fortran/adjust-args-array-descriptor.f90 @@ -0,0 +1,89 @@ +! Test array descriptor handling with the need_device_addr modifier to adjust_args + +module m + use iso_c_binding + implicit none (type, external) + + integer :: case = 0 +contains + subroutine var_array_alloc(x) + integer, allocatable :: x(:) + !$omp target has_device_addr(x) + block + if (size(x) /= 3) stop 1 + if (any (x /= [1,2,3])) stop 2 + x = x * (-1) + end block + end + + subroutine base_array_alloc(x) + !$omp declare variant(var_array_alloc) match(construct={dispatch}) adjust_args(need_device_addr : x) + integer, allocatable :: x(:) + error stop + end + + subroutine var_array_nonalloc(x) + integer :: x(:) + !$omp target has_device_addr(x) + block + if (size(x) /= 4) stop 3 + if (any (x /= [11,22,33,44])) stop 4 + x = x * (-1) + end block + end + + subroutine base_array_nonalloc(x) + !$omp declare variant(var_array_nonalloc) match(construct={dispatch}) adjust_args(need_device_addr : x) + integer :: x(:) + error stop + end + + subroutine test_array_alloc(y) + integer, allocatable :: y(:) + !$omp target enter data map(y) + + + ! Direct call (for testing; value check fails if both are enabled + ! !$omp target data use_device_addr(y) + ! call var_array_alloc (y) + ! !$omp end target data + + !$omp dispatch + call base_array_alloc (y) + + !$omp target exit data map(y) + + if (size(y) /= 3) stop 3 + if (any (y /= [-1,-2,-3])) stop 1 + end + + subroutine test_array_nonalloc() + integer :: y(4) + y = [11,22,33,44] + + !$omp target enter data map(y) + + ! Direct call (for testing; value check fails if both are enabled + !!$omp target data use_device_addr(y) + ! call var_array_nonalloc (y) + !!$omp end target data + + !$omp dispatch + call base_array_nonalloc (y) + + !$omp target exit data map(y) + + if (size(y) /= 4) stop 3 + if (any (y /= [-11,-22,-33,-44])) stop 1 + end +end module + +use m +implicit none +integer, allocatable :: z(:) + +z = [1,2,3] +call test_array_alloc(z) +call test_array_nonalloc() + +end diff --git a/libgomp/testsuite/libgomp.fortran/need-device-ptr.f90 b/libgomp/testsuite/libgomp.fortran/need-device-ptr.f90 new file mode 100644 index 000000000000..c75688c34862 --- /dev/null +++ b/libgomp/testsuite/libgomp.fortran/need-device-ptr.f90 @@ -0,0 +1,132 @@ +! Comprehensive non-array testcase for need_device_ptr / need_device_addr + +module m + use iso_c_binding + implicit none (type, external) + + integer :: case = 0 +contains + subroutine var_ptr_f(n, x, y, z) + integer, value :: n + type(c_ptr) :: x + type(c_ptr), value :: y + type(c_ptr), optional :: z + !$omp target is_device_ptr(x,y,z) + block + integer, pointer :: ix, iy, iz + call c_f_pointer(x, ix) + call c_f_pointer(y, iy) + call c_f_pointer(z, iz) + if (ix /= 52) stop n*10 + 1 + if (iy /= 85) stop n*10 + 2 + if (iz /= 52) stop n*10 + 5 + end block + end + subroutine base_ptr_f(n, x, y, z) + !$omp declare variant(var_ptr_f) match(construct={dispatch}) adjust_args(need_device_ptr : x, y, z) + integer, value :: n + type(c_ptr) :: x + type(c_ptr), value :: y + type(c_ptr), optional :: z + error stop n + end + + subroutine var_caddr_f(x, y) + type(c_ptr) :: x + type(c_ptr), optional :: y + !$omp target has_device_addr(x, y) + block + integer, pointer :: ix, iy + call c_f_pointer(x, ix) + call c_f_pointer(x, iy) + if (ix /= 52) stop 3 + if (iy /= 85) stop 6 + end block + end +! FIXME: optional args give a "sorry". +! subroutine base_caddr_f(x, y) +! !$omp declare variant(var_caddr_f) match(construct={dispatch}) adjust_args(need_device_addr : x, y) +! type(c_ptr) :: x +! type(c_ptr), optional :: y +! error stop +! end + + subroutine var_iaddr_f(x,y) + integer :: x + integer, optional :: y + !$omp target has_device_addr(x, y) + block + if (x /= 52) stop 4 + if (y /= 85) stop 4 + end block + end + +! FIXME: optional args give a "sorry". +! subroutine base_iaddr_f(x,y) +! !$omp declare variant(var_iaddr_f) match(construct={dispatch}) adjust_args(need_device_addr : x, y) +! integer :: x +! integer, optional :: y +! error stop +! end + + subroutine test_f(carg1, carg2, carg1v, carg2v, iarg1, iarg2) + type(c_ptr) :: carg1, carg2 + type(c_ptr), value :: carg1v, carg2v + integer, target :: iarg1, iarg2 + type(c_ptr) :: cptr1, cptr2 + integer, target :: ivar1, ivar2 + + + ivar1 = 52 + ivar2 = 85 + + !$omp target enter data map(to: ivar1, ivar2) + + cptr1 = c_loc(ivar1) + cptr2 = c_loc(ivar2) + + !$omp dispatch + call base_ptr_f (1, carg1, carg2, carg1) + !$omp dispatch + call base_ptr_f (2, carg1v, carg2v, carg1v) + !$omp dispatch + call base_ptr_f (3, cptr1, cptr2, cptr1) + !$omp dispatch + call base_ptr_f (4, c_loc(iarg1), c_loc(iarg2), c_loc(iarg1)) + !$omp dispatch + call base_ptr_f (6, c_loc(ivar1), c_loc(ivar2), c_loc(ivar1)) + +! FIXME: optional argument functions not supported yet. +! !$omp dispatch +! call base_caddr_f (carg1, carg2) +! !$omp dispatch +! call base_caddr_f (carg1v, carg2v) +! !$omp dispatch +! call base_caddr_f (cptr1, cptr2) +! !$omp dispatch +! call base_caddr_f (c_loc(iarg1), c_loc(iarg2)) +! !$omp dispatch +! call base_caddr_f (c_loc(ivar1), c_loc(ivar2)) +! !$omp dispatch +! call base_iaddr_f (iarg1, iarg2) +! !$omp dispatch +! call base_iaddr_f (ivar1, iarg2) + + !$omp target exit data map(release: ivar1, ivar2) + end +end module m + +use m +implicit none +integer, target :: mx, my +type(c_ptr) :: cptr1, cptr2 +mx = 52 +my = 85 + +cptr1 = c_loc(mx) +cptr2 = c_loc(my) + +!$omp target data map(to: mx, my) + call test_f (cptr1, cptr2, cptr1, cptr2, mx, my) +!$omp end target data +end