/* 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.
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);
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;
"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);
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
/* 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);
= 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:
}
}
}
- 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;
}
resolution and expansion of the CALL_EXPR EXPR. WANT_VALUE is true
if the result value of the call is needed; POINTERIZE is true if it
also needs to be pointerized. If OMP_DISPATCH_P is true, apply
- associated transformations using DISPATCH_CLAUSES and DISPATCH_LOC.
+ associated transformations using DISPATCH_CLAUSES.
This function may return either the original call or some other
expression such as a conditional to select one of multiple calls.
static tree
expand_variant_call_expr (tree expr, bool want_value, bool pointerize,
- bool omp_dispatch_p,
- tree dispatch_clauses, location_t dispatch_loc)
+ bool omp_dispatch_p, tree dispatch_clauses)
{
/* If we've already processed this call, stop now. This can happen
if the variant call resolves to the original function, or to
if (omp_dispatch_p)
thiscall = modify_call_for_omp_dispatch (thiscall,
dispatch_clauses,
- dispatch_loc);
+ want_value,
+ pointerize);
if (!tail)
tail = thiscall;
else
if (omp_dispatch_p)
thiscall = modify_call_for_omp_dispatch (thiscall,
dispatch_clauses,
- dispatch_loc);
+ want_value,
+ pointerize);
}
if (pointerize)
thiscall = build_fold_addr_expr_loc (loc, thiscall);
|| TREE_ADDRESSABLE (type)))
pointerize = true;
- if (omp_dispatch_p)
- return expand_variant_call_expr (expr, want_value, pointerize,
- omp_dispatch_p,
- gimplify_omp_ctxp->clauses,
- gimplify_omp_ctxp->location);
- else
- return expand_variant_call_expr (expr, want_value, pointerize,
- omp_dispatch_p,
- NULL_TREE, UNKNOWN_LOCATION);
+ return expand_variant_call_expr (expr, want_value, pointerize,
+ omp_dispatch_p,
+ (omp_dispatch_p
+ ? gimplify_omp_ctxp->clauses
+ : NULL_TREE));
}
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" } */
#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);
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;
}
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 } */
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>
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);
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 } */
#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);
#pragma omp dispatch
base3<int*>(a, 1, 2, "abc");
- /* { dg-note "required by 'dispatch' construct" "" { target *-*-* } .-2 } */
return x;
}