https://gcc.gnu.org/g:8110f3d036ed33770e5a2f0ab89b3600c26df457
commit 8110f3d036ed33770e5a2f0ab89b3600c26df457 Author: Sandra Loosemore <sloosem...@baylibre.com> Date: Wed Mar 26 21:09:36 2025 +0000 OpenMP: Create additional interop objects with append_args This patch adds support for the case where #pragma omp declare variant with append_args is used inside a #pragma omp dispatch interop that specifies fewer interop args than required by the variant; new interop objects are implicitly created and then destroyed around the call to the variant, using the GOMP_interop builtin. This is a backport of commit f016ee89955ab4da5fe7ef89368e9437bb5ffb13 from mainline. gcc/fortran/ChangeLog * trans-openmp.cc (gfc_trans_omp_declare_variant): Remove accidental redeclaration of pref. gcc/ChangeLog * gimplify.cc (modify_call_for_omp_dispatch): Adjust arguments. Remove the "sorry" for the case where new interop objects must be constructed, and add code to make it work instead. (gimplify_variant_call_expr): Re-work want_value/pointerize logic and adjust the calls to modify_call_for_omp_dispatch. gcc/testsuite/ChangeLog * c-c++-common/gomp/append-args-1.c: Adjust expected behavior. * c-c++-common/gomp/append-args-interop.c: New. * c-c++-common/gomp/dispatch-11.c: Adjust expected behavior. * g++.dg/gomp/append-args-1.C: Likewise. * gfortran.dg/gomp/append-args-interop.f90: New. * gfortran.dg/gomp/declare-variant-mod-2.f90: Adjust expected behavior. libgomp/ChangeLog * libgomp.texi (OpenMP 5.1): Mark append_args as fully supported. Co-Authored-By: Tobias Burnus <tbur...@baylibre.com> Diff: --- gcc/fortran/trans-openmp.cc | 4 +- gcc/gimplify.cc | 226 ++++++++++++++++++--- gcc/testsuite/c-c++-common/gomp/append-args-1.c | 14 +- .../c-c++-common/gomp/append-args-interop.c | 44 ++++ gcc/testsuite/c-c++-common/gomp/dispatch-11.c | 3 - gcc/testsuite/g++.dg/gomp/append-args-1.C | 18 +- .../gfortran.dg/gomp/append-args-interop.f90 | 27 +++ .../gfortran.dg/gomp/declare-variant-mod-2.f90 | 6 - libgomp/libgomp.texi | 3 +- 9 files changed, 278 insertions(+), 67 deletions(-) diff --git a/gcc/fortran/trans-openmp.cc b/gcc/fortran/trans-openmp.cc index b226cf5b231b..534e5b769eae 100644 --- a/gcc/fortran/trans-openmp.cc +++ b/gcc/fortran/trans-openmp.cc @@ -11628,8 +11628,8 @@ gfc_trans_omp_declare_variant (gfc_namespace *ns, gfc_namespace *parent_ns) tree pref = NULL_TREE; if (n->u.init.len) { - tree pref = build_string (n->u.init.len, - n->u2.init_interop); + pref = build_string (n->u.init.len, + n->u2.init_interop); TREE_TYPE (pref) = build_array_type_nelts ( unsigned_char_type_node, n->u.init.len); diff --git a/gcc/gimplify.cc b/gcc/gimplify.cc index 042dd6f32fcf..9592b5f8043d 100644 --- a/gcc/gimplify.cc +++ b/gcc/gimplify.cc @@ -3894,8 +3894,8 @@ maybe_fold_stmt (gimple_stmt_iterator *gsi) /* OpenMP: Handle the append_args and adjust_args clauses of declare_variant for EXPR, which is a CALL_EXPR whose CALL_EXPR_FN - is the variant, within a dispatch construct with clauses DISPATCH_CLAUSES - and location DISPATCH_LOC. + is the variant, within a dispatch construct with clauses DISPATCH_CLAUSES. + WANT_VALUE and POINTERIZE are as for expand_variant_call_expr. 'append_args' causes interop objects are added after the last regular (nonhidden, nonvariadic) arguments of the variant function. @@ -3905,7 +3905,7 @@ maybe_fold_stmt (gimple_stmt_iterator *gsi) address. */ static tree modify_call_for_omp_dispatch (tree expr, tree dispatch_clauses, - location_t dispatch_loc) + bool want_value, bool pointerize) { tree fndecl = get_callee_fndecl (expr); @@ -3913,9 +3913,11 @@ modify_call_for_omp_dispatch (tree expr, tree dispatch_clauses, if (!fndecl) return expr; + tree init_code = NULL_TREE; + tree cleanup = NULL_TREE; + tree clobbers = NULL_TREE; int nargs = call_expr_nargs (expr); tree dispatch_device_num = NULL_TREE; - tree dispatch_device_num_init = NULL_TREE; tree dispatch_interop = NULL_TREE; tree dispatch_append_args = NULL_TREE; int nfirst_args = 0; @@ -3976,14 +3978,6 @@ modify_call_for_omp_dispatch (tree expr, tree dispatch_clauses, "the %<device%> clause must be present if the %<interop%> " "clause has more than one list item"); } - if (dispatch_append_args && nappend != ninterop) - { - sorry_at (EXPR_LOCATION (TREE_PURPOSE (dispatch_append_args)), - "%<append_args%> clause not yet supported for %qD, except " - "when specifying all %d objects in the %<interop%> clause " - "of the %<dispatch%> directive", fndecl, nappend); - inform (dispatch_loc, "required by %<dispatch%> construct"); - } else if (dispatch_append_args) { tree *buffer = XALLOCAVEC (tree, nargs + nappend); @@ -3996,11 +3990,153 @@ modify_call_for_omp_dispatch (tree expr, tree dispatch_clauses, arg = TREE_CHAIN (arg); buffer[i] = CALL_EXPR_ARG (expr, i); } - int j = nappend; + int j = ninterop; for (tree t = dispatch_interop; t; t = TREE_CHAIN (t)) if (OMP_CLAUSE_CODE (t) == OMP_CLAUSE_INTEROP) buffer[i + --j] = OMP_CLAUSE_DECL (t); gcc_checking_assert (j == 0); + + /* Do we need to create additional interop objects? */ + if (ninterop < nappend) + { + if (dispatch_device_num == NULL_TREE) + /* Not remapping device number. */ + dispatch_device_num = build_int_cst (integer_type_node, + GOMP_DEVICE_DEFAULT_OMP_61); + int nnew = nappend - ninterop; + tree nobjs = build_int_cst (integer_type_node, nnew); + tree a, t; + + /* Skip to the append_args clause for the first constructed + interop argument. */ + tree apparg = dispatch_append_args; + for (j = 0; j < ninterop; j++) + apparg = TREE_CHAIN (apparg); + + /* omp_interop_t *objs[n]; */ + tree objtype = build_pointer_type (pointer_sized_int_node); + t = build_array_type_nelts (objtype, nnew); + tree objs = create_tmp_var (t, "interopobjs"); + + /* int target_tgtsync[n]; */ + t = build_array_type_nelts (integer_type_node, nnew); + tree target_tgtsync = create_tmp_var (t, "tgt_tgtsync"); + + /* Scan first to determine if we need a prefer_type array. */ + tree prefer_type = NULL_TREE; + tree prefer_type_type = NULL_TREE; + for (j = ninterop, a = apparg; j < nappend; j++, a = TREE_CHAIN (a)) + if (TREE_VALUE (a) != NULL_TREE) + { + /* const char *prefer_type[n]; */ + t = build_qualified_type (char_type_node, TYPE_QUAL_CONST); + prefer_type_type = build_pointer_type (t); + t = build_array_type_nelts (prefer_type_type, nnew); + prefer_type = create_tmp_var (t, "pref_type"); + break; + } + + /* Initialize the arrays, generating temp vars and clobbers for + the interobject objects. (The constructed array holding the + pointers to these objects shouldn't need clobbering as there's + no reason for GOMP_interop to modify its contents.) */ + for (j = ninterop, a = apparg; j < nappend; j++, a = TREE_CHAIN (a)) + { + /* The allocated temporaries for the interop objects + have type omp_interop_t, which is an integer type that + can encode a pointer. */ + tree objvar = create_tmp_var (pointer_sized_int_node, "interop"); + buffer[i + j] = objvar; + TREE_ADDRESSABLE (objvar) = 1; + /* Generate a clobber for the temporary for when we're done + with it. */ + tree c = build_clobber (pointer_sized_int_node, + CLOBBER_OBJECT_END); + c = build2 (MODIFY_EXPR, pointer_sized_int_node, objvar, c); + if (clobbers) + clobbers = build2 (COMPOUND_EXPR, TREE_TYPE (clobbers), + c, clobbers); + else + clobbers = c; + + /* objs[offset] = &objvar; */ + tree offset = build_int_cst (integer_type_node, j - ninterop); + tree init = build4 (ARRAY_REF, objtype, objs, offset, + NULL_TREE, NULL_TREE); + init = build2 (MODIFY_EXPR, objtype, init, + build_fold_addr_expr (objvar)); + if (init_code) + init_code = build2 (COMPOUND_EXPR, TREE_TYPE (init), + init_code, init); + else + init_code = init; + + /* target_tgtsync[offset] = tgt; + (Don't blame me, I didn't design the encoding of this + info into the dispatch interop clause data structure, + but the runtime wants a bit mask.) */ + tree tree_tgt = TREE_OPERAND (TREE_PURPOSE (a), 0); + int tgt = 0; + if (TREE_PURPOSE (tree_tgt) == boolean_true_node) + tgt |= GOMP_INTEROP_TARGET; + if (TREE_VALUE (tree_tgt) == boolean_true_node) + tgt |= GOMP_INTEROP_TARGETSYNC; + init = build4 (ARRAY_REF, integer_type_node, + target_tgtsync, offset, NULL_TREE, NULL_TREE); + init = build2 (MODIFY_EXPR, integer_type_node, init, + build_int_cst (integer_type_node, tgt)); + init_code = build2 (COMPOUND_EXPR, TREE_TYPE (init), + init_code, init); + + if (prefer_type) + { + tree pref = TREE_VALUE (a); + if (pref == NULL_TREE) + pref = null_pointer_node; + else if (TREE_CODE (pref) == TREE_LIST) + { + /* FIXME: this is a bug in the C++ front end. */ + sorry_at (OMP_CLAUSE_LOCATION (dispatch_interop), + "%<prefer_type%> with template function"); + pref = null_pointer_node; + } + else + pref = build_fold_addr_expr (pref); + init = build4 (ARRAY_REF, prefer_type_type, prefer_type, + offset, NULL_TREE, NULL_TREE); + init = build2 (MODIFY_EXPR, prefer_type_type, init, + pref); + init_code = build2 (COMPOUND_EXPR, TREE_TYPE (init), + init_code, init); + } + } + + tree fn = builtin_decl_explicit (BUILT_IN_GOMP_INTEROP); + tree create + = build_call_expr (fn, 11, dispatch_device_num, + nobjs, objs, target_tgtsync, + prefer_type ? prefer_type : null_pointer_node, + integer_zero_node, null_pointer_node, + integer_zero_node, null_pointer_node, + integer_zero_node, null_pointer_node); + if (init_code) + init_code = build2 (COMPOUND_EXPR, TREE_TYPE (create), + init_code, create); + else + init_code = create; + + cleanup + = build_call_expr (fn, 11, dispatch_device_num, + integer_zero_node, null_pointer_node, + null_pointer_node, null_pointer_node, + integer_zero_node, null_pointer_node, + nobjs, objs, + integer_zero_node, null_pointer_node); + if (clobbers) + cleanup = build2 (COMPOUND_EXPR, TREE_TYPE (clobbers), + cleanup, clobbers); + } + for (j = 0; j < nappend; j++) { /* Fortran permits by-reference or by-value for the dummy arg @@ -4060,8 +4196,9 @@ modify_call_for_omp_dispatch (tree expr, tree dispatch_clauses, /* Nothing to do for adjust_args? */ if (!dispatch_adjust_args_list || !TYPE_ARG_TYPES (TREE_TYPE (fndecl))) - return expr; + goto add_cleanup; + /* Handle adjust_args. */ for (int i = 0; i < nargs; i++) { tree *arg_p = &CALL_EXPR_ARG (expr, i); @@ -4146,9 +4283,14 @@ modify_call_for_omp_dispatch (tree expr, tree dispatch_clauses, = builtin_decl_explicit (BUILT_IN_OMP_GET_DEFAULT_DEVICE); tree call = build_call_expr (fn, 0); dispatch_device_num = create_tmp_var_raw (TREE_TYPE (call)); - dispatch_device_num_init + tree init = build4 (TARGET_EXPR, TREE_TYPE (call), dispatch_device_num, call, NULL_TREE, NULL_TREE); + if (init_code) + init_code = build2 (COMPOUND_EXPR, TREE_TYPE (init), + init_code, init); + else + init_code = init; } // We want to emit the following statement: @@ -4183,9 +4325,35 @@ modify_call_for_omp_dispatch (tree expr, tree dispatch_clauses, } } } - if (dispatch_device_num_init) - expr = build2 (COMPOUND_EXPR, TREE_TYPE (expr), - dispatch_device_num_init, expr); + + add_cleanup: + if (cleanup) + { + tree result = NULL_TREE; + if (want_value && pointerize) + { + tree tmp = create_tmp_var (build_pointer_type (TREE_TYPE (expr)), + "cleanuptmp"); + result = build_simple_mem_ref (tmp); + expr = build2 (INIT_EXPR, TREE_TYPE (tmp), tmp, + build_fold_addr_expr (expr)); + } + else if (want_value) + { + tree tmp = create_tmp_var (TREE_TYPE (expr), "cleanuptmp"); + result = tmp; + expr = build2 (INIT_EXPR, TREE_TYPE (tmp), tmp, expr); + } + if (init_code) + expr = build2 (COMPOUND_EXPR, TREE_TYPE (expr), init_code, expr); + expr = build2 (TRY_FINALLY_EXPR, void_type_node, expr, cleanup); + + if (result) + expr = build2 (COMPOUND_EXPR, TREE_TYPE (result), expr, result); + } + else if (init_code) + expr = build2 (COMPOUND_EXPR, TREE_TYPE (expr), init_code, expr); + return expr; } @@ -4220,6 +4388,17 @@ gimplify_variant_call_expr (tree *expr_p, gimple_seq *pre_p, vec<struct omp_variant> candidates = omp_get_dynamic_candidates (all_candidates, construct_context); + tree type = TREE_TYPE (*expr_p); + bool want_value = (fallback != fb_none && !VOID_TYPE_P (type)); + bool pointerize = false; + + /* If the result value must be an lvalue or the result type must + live in memory, then we have to pointerize it if we need a temporary. */ + if (want_value + && ((!(fallback & fb_rvalue) && (fallback & fb_lvalue)) + || TREE_ADDRESSABLE (type))) + pointerize = true; + /* If the variant call could be resolved now, build a nest of COND_EXPRs if there are dynamic candidates, and/or a new CALL_EXPR for each candidate call. */ @@ -4254,7 +4433,7 @@ gimplify_variant_call_expr (tree *expr_p, gimple_seq *pre_p, thiscall = modify_call_for_omp_dispatch (thiscall, gimplify_omp_ctxp->clauses, - gimplify_omp_ctxp->location); + want_value, pointerize); if (!tail) tail = thiscall; else @@ -4276,9 +4455,6 @@ gimplify_variant_call_expr (tree *expr_p, gimple_seq *pre_p, /* If we need a usable return value, we need a temporary and an assignment in each alternative. This logic was borrowed from gimplify_cond_expr. */ - tree type = TREE_TYPE (*expr_p); - bool want_value = (fallback != fb_none && !VOID_TYPE_P (type)); - bool pointerize = false; tree tmp = NULL_TREE, result = NULL_TREE; if (want_value) @@ -4286,8 +4462,7 @@ gimplify_variant_call_expr (tree *expr_p, gimple_seq *pre_p, /* If either an rvalue is ok or we do not require an lvalue, create the temporary. But we cannot do that if the type is addressable. */ - if (((fallback & fb_rvalue) || !(fallback & fb_lvalue)) - && !TREE_ADDRESSABLE (type)) + if (!pointerize) { tmp = create_tmp_var (type, "iftmp"); result = tmp; @@ -4296,7 +4471,6 @@ gimplify_variant_call_expr (tree *expr_p, gimple_seq *pre_p, /* Otherwise, only create and copy references to the values. */ else { - pointerize = true; type = build_pointer_type (type); tmp = create_tmp_var (type, "iftmp"); result = build_simple_mem_ref_loc (loc, tmp); @@ -4337,7 +4511,7 @@ gimplify_variant_call_expr (tree *expr_p, gimple_seq *pre_p, thiscall = modify_call_for_omp_dispatch (thiscall, gimplify_omp_ctxp->clauses, - gimplify_omp_ctxp->location); + want_value, pointerize); } if (pointerize) thiscall = build_fold_addr_expr_loc (loc, thiscall); diff --git a/gcc/testsuite/c-c++-common/gomp/append-args-1.c b/gcc/testsuite/c-c++-common/gomp/append-args-1.c index e3c31c2efc3f..bc2eebb798da 100644 --- a/gcc/testsuite/c-c++-common/gomp/append-args-1.c +++ b/gcc/testsuite/c-c++-common/gomp/append-args-1.c @@ -24,25 +24,19 @@ float base0(); float repl1(omp_interop_t, omp_interop_t); #pragma omp declare variant(repl1) match(construct={dispatch}) append_args(interop(target), interop(targetsync)) float base1(); -/* { dg-message "sorry, unimplemented: 'append_args' clause not yet supported for 'repl1', except when specifying all 2 objects in the 'interop' clause of the 'dispatch' directive" "" { target c } .-2 } */ -/* { dg-message "sorry, unimplemented: 'append_args' clause not yet supported for 'float repl1\\(omp_interop_t, omp_interop_t\\)', except when specifying all 2 objects in the 'interop' clause of the 'dispatch' directive" "" { target c++ } .-3 } */ void repl2(int *, int *, omp_interop_t, omp_interop_t); #pragma omp declare variant(repl2) match(construct={dispatch}) adjust_args(need_device_ptr : y) \ append_args(interop(target, targetsync, prefer_type(1)), \ interop(prefer_type({fr(3), attr("ompx_nop")},{fr(2)},{attr("ompx_all")}))) void base2(int *x, int *y); -/* { dg-message "sorry, unimplemented: 'append_args' clause not yet supported for 'repl2', except when specifying all 2 objects in the 'interop' clause of the 'dispatch' directive" "" { target c } .-3 } */ -/* { dg-message "sorry, unimplemented: 'append_args' clause not yet supported for 'void repl2\\(int\\*, int\\*, omp_interop_t, omp_interop_t\\)', except when specifying all 2 objects in the 'interop' clause of the 'dispatch' directive" "" { target c++ } .-4 } */ void repl3(int, omp_interop_t, ...); #pragma omp declare variant(repl3) match(construct={dispatch}) \ append_args(interop(prefer_type("cuda", "hsa"))) void base3(int, ...); -/* { dg-message "sorry, unimplemented: 'append_args' clause not yet supported for 'repl3', except when specifying all 1 objects in the 'interop' clause of the 'dispatch' directive" "" { target c } .-2 } */ -/* { dg-message "sorry, unimplemented: 'append_args' clause not yet supported for 'void repl3\\(int, omp_interop_t, \\.\\.\\.\\)', except when specifying all 1 objects in the 'interop' clause of the 'dispatch' directive" "" { target c++ } .-3 } */ -/* { dg-note "'declare variant' candidate 'repl3' declared here" "" { target c } .-4 } */ -/* { dg-note "'declare variant' candidate 'void repl3\\(int, omp_interop_t, \\.\\.\\.\\)' declared here" "" { target c++ } .-5 } */ +/* { dg-note "'declare variant' candidate 'repl3' declared here" "" { target c } .-2 } */ +/* { dg-note "'declare variant' candidate 'void repl3\\(int, omp_interop_t, \\.\\.\\.\\)' declared here" "" { target c++ } .-3 } */ float repl4(short, short, omp_interop_t, short); #pragma omp declare variant(repl4) match(construct={dispatch}) append_args(interop(target)) append_args(interop(targetsync)) /* { dg-error "too many 'append_args' clauses" } */ @@ -76,15 +70,12 @@ test (int *a, int *b) #pragma omp dispatch interop ( obj1 ) x = base1 (); - /* { dg-note "required by 'dispatch' construct" "" { target *-*-* } .-2 } */ #pragma omp dispatch interop ( obj1 ) base2 (a, b); - /* { dg-note "required by 'dispatch' construct" "" { target *-*-* } .-2 } */ #pragma omp dispatch base3 (5, 1, 2, 3); - /* { dg-note "required by 'dispatch' construct" "" { target *-*-* } .-2 } */ #pragma omp dispatch interop (obj2) base3 (5, 1, 2, 3); @@ -93,7 +84,6 @@ test (int *a, int *b) base3 (5, 1, 2, 3); /* { dg-error "number of list items in 'interop' clause \\(2\\) exceeds the number of 'append_args' items \\(1\\) for 'declare variant' candidate 'repl3'" "" { target c } .-2 } */ /* { dg-error "number of list items in 'interop' clause \\(2\\) exceeds the number of 'append_args' items \\(1\\) for 'declare variant' candidate 'void repl3\\(int, omp_interop_t, \\.\\.\\.\\)'" "" { target c++ } .-3 } */ - /* { dg-note "required by 'dispatch' construct" "" { target *-*-* } .-4 } */ return x; } diff --git a/gcc/testsuite/c-c++-common/gomp/append-args-interop.c b/gcc/testsuite/c-c++-common/gomp/append-args-interop.c new file mode 100644 index 000000000000..9494625cbbbc --- /dev/null +++ b/gcc/testsuite/c-c++-common/gomp/append-args-interop.c @@ -0,0 +1,44 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-fdump-tree-gimple" } */ + +/* Test that interop objects are implicitly created/destroyed when a dispatch + construct doesn't provide enough of them to satisfy the declare variant + append_args clause. */ + +/* The following definitions are in omp_lib, which cannot be included + in gcc/testsuite/ */ + +#if __cplusplus >= 201103L +# define __GOMP_UINTPTR_T_ENUM : __UINTPTR_TYPE__ +#else +# define __GOMP_UINTPTR_T_ENUM +#endif + +typedef enum omp_interop_t __GOMP_UINTPTR_T_ENUM +{ + omp_interop_none = 0, + __omp_interop_t_max__ = __UINTPTR_MAX__ +} omp_interop_t; + +float repl1(omp_interop_t, omp_interop_t, omp_interop_t); + +#pragma omp declare variant(repl1) match(construct={dispatch}) append_args(interop(target), interop(targetsync), interop (target)) +float base1(); + +float +test (int *a, int *b) +{ + omp_interop_t obj1; + float x; + + /* repl1 takes 3 interop arguments, one will come from the dispatch + construct and the other 2 will be consed up. */ + #pragma omp dispatch interop ( obj1 ) + x = base1 (); + + return x; +} + +/* { dg-final { scan-tree-dump "__builtin_GOMP_interop \\(D\.\[0-9\]+, 2, interopobjs\.\[0-9\]+, tgt_tgtsync\.\[0-9\]+," "gimple" } } */ +/* { dg-final { scan-tree-dump "__builtin_GOMP_interop \\(D\.\[0-9\]+, 0, 0B, 0B, 0B, 0, 0B, 2, interopobjs\.\[0-9\]+," "gimple" } } */ +/* { dg-final { scan-tree-dump "repl1 \\(obj1, interop\.\[0-9\]+, interop\.\[0-9\]+\\)" "gimple" } } */ diff --git a/gcc/testsuite/c-c++-common/gomp/dispatch-11.c b/gcc/testsuite/c-c++-common/gomp/dispatch-11.c index e59985a5691c..79dcd0a409e9 100644 --- a/gcc/testsuite/c-c++-common/gomp/dispatch-11.c +++ b/gcc/testsuite/c-c++-common/gomp/dispatch-11.c @@ -87,12 +87,9 @@ test (int *a, int *b) base3 (a, b); /* { dg-error "number of list items in 'interop' clause \\(2\\) exceeds the number of 'append_args' items \\(1\\) for 'declare variant' candidate 'repl3'" "" { target c } .-2 } */ /* { dg-error "number of list items in 'interop' clause \\(2\\) exceeds the number of 'append_args' items \\(1\\) for 'declare variant' candidate 'void repl3\\(int\\*, int\\*, omp_interop_t\\)'" "" { target c++ } .-3 } */ - /* { dg-note "required by 'dispatch' construct" "" { target *-*-* } .-4 } */ #pragma omp dispatch interop(obj3) base3 (a, b); - /* { dg-message "sorry, unimplemented: 'append_args' clause not yet supported for 'repl3'" "" { target c } 28 } */ - /* { dg-message "sorry, unimplemented: 'append_args' clause not yet supported for 'void repl3\\(int\\*, int\\*, omp_interop_t\\)'" "" { target c++ } 28 } */ return x + y; } diff --git a/gcc/testsuite/g++.dg/gomp/append-args-1.C b/gcc/testsuite/g++.dg/gomp/append-args-1.C index 1f0a72447563..6e795869ec1c 100644 --- a/gcc/testsuite/g++.dg/gomp/append-args-1.C +++ b/gcc/testsuite/g++.dg/gomp/append-args-1.C @@ -20,8 +20,6 @@ template<typename T> float base1(T); -/* { dg-message "sorry, unimplemented: 'append_args' clause not yet supported for 'float repl1\\(T, T2, T2\\) \\\[with T = omp_interop_t; T2 = omp_interop_t\\\]', except when specifying all 2 objects in the 'interop' clause of the 'dispatch' directive" "" { target *-*-* } .-5 } */ -/* { dg-message "sorry, unimplemented: 'append_args' clause not yet supported for 'float repl1\\(T, T2, T2\\) \\\[with T = float; T2 = omp_interop_t\\\]', except when specifying all 2 objects in the 'interop' clause of the 'dispatch' directive" "" { target *-*-* } .-6 } */ @@ -45,8 +43,6 @@ void repl99(T); append_args(interop(target, targetsync, prefer_type("cuda"))) void base99(); -/* { dg-message "sorry, unimplemented: 'append_args' clause not yet supported for 'void repl99\\(T\\) \\\[with T = omp_interop_t\\\]', except when specifying all 1 objects in the 'interop' clause of the 'dispatch' directive" "" { target *-*-* } .-3 } */ - template<typename T, typename T2, typename T3> @@ -57,9 +53,6 @@ void repl2(T, T2, T3, T3); template<typename T, typename T2> void base2(T x, T2 y); -/* { dg-message "sorry, unimplemented: 'append_args' clause not yet supported for 'void repl2\\(T, T2, T3, T3\\) \\\[with T = int\\*; T2 = int\\*; T3 = omp_interop_t\\\]', except when specifying all 2 objects in the 'interop' clause of the 'dispatch' directive" "" { target *-*-* } .-5 } */ -/* { dg-message "sorry, unimplemented: 'append_args' clause not yet supported for 'void repl2\\(T, T2, T3, T3\\) \\\[with T = int\\*; T2 = omp_interop_t; T3 = omp_interop_t\\\]', except when specifying all 2 objects in the 'interop' clause of the 'dispatch' directive" "" { target *-*-* } .-6 } */ - template<typename T,typename T3> void tooFewRepl(T, T, T3); @@ -83,7 +76,6 @@ void repl3(T, T2, ...); template<typename T> void base3(T, ...); -/* { dg-message "sorry, unimplemented: 'append_args' clause not yet supported for 'void repl3\\(T, T2, \.\.\.\\) \\\[with T = int\\*; T2 = omp_interop_t\\\]', except when specifying all 1 objects in the 'interop' clause of the 'dispatch' directive" "" { target *-*-* } .-4 } */ @@ -104,23 +96,18 @@ test (int *a, int *b) #pragma omp dispatch base99 (); - /* { dg-note "required by 'dispatch' construct" "" { target *-*-* } .-2 } */ - #pragma omp dispatch interop ( obj1 ) + #pragma omp dispatch interop ( obj1 ) // { dg-message "sorry" } base2<int *, omp_interop_t> (b, omp_interop_none); - /* { dg-note "required by 'dispatch' construct" "" { target *-*-* } .-2 } */ - #pragma omp dispatch interop ( obj1 ) + #pragma omp dispatch interop ( obj1 ) // { dg-message "sorry" } base2<int *, int *> (b, a); - /* { dg-note "required by 'dispatch' construct" "" { target *-*-* } .-2 } */ #pragma omp dispatch interop ( obj1 ) x = base1<omp_interop_t> (omp_interop_none); - /* { dg-note "required by 'dispatch' construct" "" { target *-*-* } .-2 } */ #pragma omp dispatch interop ( obj1 ) x = base1<float> (1.0f); - /* { dg-note "required by 'dispatch' construct" "" { target *-*-* } .-2 } */ #pragma omp dispatch tooFewBase<int*,int*>(a,b); @@ -130,7 +117,6 @@ test (int *a, int *b) #pragma omp dispatch base3<int*>(a, 1, 2, "abc"); - /* { dg-note "required by 'dispatch' construct" "" { target *-*-* } .-2 } */ return x; } diff --git a/gcc/testsuite/gfortran.dg/gomp/append-args-interop.f90 b/gcc/testsuite/gfortran.dg/gomp/append-args-interop.f90 new file mode 100644 index 000000000000..11a0f01daa46 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/gomp/append-args-interop.f90 @@ -0,0 +1,27 @@ +! { dg-do compile } +! { dg-additional-options "-fdump-tree-gimple" } + +! Test that interop objects are implicitly created/destroyed when a dispatch +! construct doesn't provide enough of them to satisfy the declare variant +! append_args clause. + +module m + use omp_lib, only: omp_interop_kind +contains +subroutine g(x,y,z) + integer(omp_interop_kind) :: x, y, z + value :: y +end +subroutine f() + !$omp declare variant(f: g) append_args(interop(target), interop(prefer_type("cuda","hip"), targetsync), interop(target,targetsync,prefer_type({attr("ompx_foo")}))) match(construct={dispatch}) +end +end + +use m +!$omp dispatch device(99) + call f() +end + +! { dg-final { scan-tree-dump "__builtin_GOMP_interop \\(99, 3, interopobjs\.\[0-9\]+, tgt_tgtsync\.\[0-9\]+, pref_type\.\[0-9\]+, " "gimple" } } +! { dg-final { scan-tree-dump "__builtin_GOMP_interop \\(99, 0, 0B, 0B, 0B, 0, 0B, 3, interopobjs\.\[0-9\]+," "gimple" } } +! { dg-final { scan-tree-dump "g \\(&interop\.\[0-9\]+, interop\.\[0-9\]+, &interop\.\[0-9\]+\\)" "gimple" } } diff --git a/gcc/testsuite/gfortran.dg/gomp/declare-variant-mod-2.f90 b/gcc/testsuite/gfortran.dg/gomp/declare-variant-mod-2.f90 index f75b49ce0637..ab4405056a9e 100644 --- a/gcc/testsuite/gfortran.dg/gomp/declare-variant-mod-2.f90 +++ b/gcc/testsuite/gfortran.dg/gomp/declare-variant-mod-2.f90 @@ -9,12 +9,6 @@ ! { dg-error "'x' at .1. is specified more than once" "" { target *-*-* } 17 } -! { dg-message "sorry, unimplemented: 'append_args' clause not yet supported for 'm2_f1', except when specifying all 1 objects in the 'interop' clause of the 'dispatch' directive" "" { target *-*-* } 27 } -! { dg-note "required by 'dispatch' construct" "" { target *-*-* } 33 } -! { dg-message "sorry, unimplemented: 'append_args' clause not yet supported for 'm2_f2', except when specifying all 2 objects in the 'interop' clause of the 'dispatch' directive" "" { target *-*-* } 27 } -! { dg-note "required by 'dispatch' construct" "" { target *-*-* } 37 } -! { dg-message "sorry, unimplemented: 'append_args' clause not yet supported for 'm2_f3', except when specifying all 3 objects in the 'interop' clause of the 'dispatch' directive" "" { target *-*-* } 27 } -! { dg-note "required by 'dispatch' construct" "" { target *-*-* } 43 } ! Check that module-file handling works for declare_variant ! and its match/adjust_args/append_args clauses diff --git a/libgomp/libgomp.texi b/libgomp/libgomp.texi index a6d03852f456..e303cb513c5a 100644 --- a/libgomp/libgomp.texi +++ b/libgomp/libgomp.texi @@ -293,8 +293,7 @@ The OpenMP 4.5 specification is fully supported. @item C/C++'s @code{declare variant} directive: elision support of preprocessed code @tab N @tab @item @code{declare variant}: new clauses @code{adjust_args} and - @code{append_args} @tab P @tab For @code{append_args}, all interop objects - must be specified in the @code{interop} clause of @code{dispatch} + @code{append_args} @tab Y @tab @item @code{dispatch} construct @tab Y @tab @item device-specific ICV settings with environment variables @tab Y @tab @item @code{assume} and @code{assumes} directives @tab Y @tab