On 3/8/25 11:40, Tobias Burnus wrote:
[snip]

LGTM – but I would prefer if we could make the scan-tree-dump check of the new test case a bit stricter, just to avoid that we accidentally regress on this when modifying the patch.

OK. I've pushed the attached version of the patch with a few tweaks to the new testcase append-args-dynamic.c to get more test coverage, and testing for more as well as more specific things in the gimple dump. The rest of the patch is identical to the previously-posted version.

BTW, I feel rather guilty about getting this in so late in stage 4 and hope we will not have many more OpenMP patches or bug fixes in GCC 15 that touch non-OpenMP code. :-(

-Sandra
From 4c0786e5dc467b5e3e4c18c0e39c8155d9c8760e Mon Sep 17 00:00:00 2001
From: Sandra Loosemore <sloosem...@baylibre.com>
Date: Sun, 9 Mar 2025 01:50:19 +0000
Subject: [PATCH] OpenMP: Integrate dynamic selectors with dispatch argument
 handling [PR118457]

Support for dynamic selectors in "declare variant" was developed in
parallel with support for the adjust_args/append_args clauses and the
dispatch construct; they collided in a bad way.  This patch fixes the
"sorry" for calls that need both by removing the adjust_args/append_args
code from gimplify_call_expr and invoking it from the new variant
substitution code instead.  It's handled as a tree -> tree transformation
rather than tree -> gimple because eventually this code may end up being
invoked from the front ends instead of the gimplifier (see PR115076).

gcc/ChangeLog
	PR middle-end/118457
	* gimplify.cc (modify_call_for_omp_dispatch): New, containing
	code split from gimplify_call_expr and modified to emit tree
	instead of gimple.  Remove the error for falling through to a call
	to the base function.
	(expand_variant_call_expr): New, split from gimplify_variant_call_expr.
	Call modify_call_for_omp_dispatch on calls to
	variants in a dispatch construct context.
	(gimplify_variant_call_expr): Make it call expand_variant_call_expr
	to do the actual work.
	(gimplify_call_expr): Remove sorry for calls involving both
	dynamic/late selectors and adjust_args/append_args, and adjust
	for new interface.  Move adjust_args/append_args code to
	modify_call_for_omp_dispatch.
	(gimplify_omp_dispatch): Add some comments.

gcc/testsuite/ChangeLog
	PR middle-end/118457
	* c-c++-common/gomp/adjust-args-6.c: Remove xfails and adjust
	expected output.
	* c-c++-common/gomp/append-args-5.c: Adjust expected output.
	* c-c++-common/gomp/append-args-dynamic.c: New.
	* c-c++-common/gomp/dispatch-11.c: Adjust expected output.
	* gfortran.dg/gomp/dispatch-11.f90: Likewise.
---
 gcc/gimplify.cc                               | 815 +++++++++---------
 .../c-c++-common/gomp/adjust-args-6.c         |  13 +-
 .../c-c++-common/gomp/append-args-5.c         |  19 +-
 .../c-c++-common/gomp/append-args-dynamic.c   |  94 ++
 gcc/testsuite/c-c++-common/gomp/dispatch-11.c |  22 +-
 .../gfortran.dg/gomp/dispatch-11.f90          |   5 -
 6 files changed, 501 insertions(+), 467 deletions(-)
 create mode 100644 gcc/testsuite/c-c++-common/gomp/append-args-dynamic.c

diff --git a/gcc/gimplify.cc b/gcc/gimplify.cc
index 6869f53ce70..5bdd970f570 100644
--- a/gcc/gimplify.cc
+++ b/gcc/gimplify.cc
@@ -3872,29 +3872,331 @@ find_supercontext (void)
   return NULL_TREE;
 }
 
+/* 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.
+
+   'append_args' causes interop objects are added after the last regular
+   (nonhidden, nonvariadic) arguments of the variant function.
+   'adjust_args' with need_device_{addr,ptr} converts the pointer target of
+   a pointer from a host to a device address. This uses either the default
+   device or the passed device number, which then sets the default device
+   address.  */
+static tree
+modify_call_for_omp_dispatch (tree expr, tree dispatch_clauses,
+			      location_t dispatch_loc)
+{
+  tree fndecl = get_callee_fndecl (expr);
+
+  /* Skip processing if we don't get the expected call form.  */
+  if (!fndecl)
+    return expr;
+
+  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;
+  tree dispatch_adjust_args_list
+    = lookup_attribute ("omp declare variant variant args",
+			DECL_ATTRIBUTES (fndecl));
+
+  if (dispatch_adjust_args_list)
+    {
+      dispatch_adjust_args_list = TREE_VALUE (dispatch_adjust_args_list);
+      dispatch_append_args = TREE_CHAIN (dispatch_adjust_args_list);
+      if (TREE_PURPOSE (dispatch_adjust_args_list) == NULL_TREE
+	  && TREE_VALUE (dispatch_adjust_args_list) == NULL_TREE)
+	dispatch_adjust_args_list = NULL_TREE;
+    }
+  if (dispatch_append_args)
+    {
+      nfirst_args = tree_to_shwi (TREE_PURPOSE (dispatch_append_args));
+      dispatch_append_args = TREE_VALUE (dispatch_append_args);
+    }
+  dispatch_device_num = omp_find_clause (dispatch_clauses, OMP_CLAUSE_DEVICE);
+  if (dispatch_device_num)
+    dispatch_device_num = OMP_CLAUSE_DEVICE_ID (dispatch_device_num);
+  dispatch_interop = omp_find_clause (dispatch_clauses, OMP_CLAUSE_INTEROP);
+  int nappend = 0, ninterop = 0;
+  for (tree t = dispatch_append_args; t; t = TREE_CHAIN (t))
+    nappend++;
+
+  /* FIXME: error checking should be taken out of this function and
+     handled before any attempt at filtering or resolution happens.
+     Otherwise whether or not diagnostics appear is determined by
+     GCC internals, how good the front ends are at constant-folding,
+     the split between early/late resolution, etc instead of the code
+     as written by the user.  */
+  if (dispatch_interop)
+    {
+      for (tree t = dispatch_interop; t; t = TREE_CHAIN (t))
+	if (OMP_CLAUSE_CODE (t) == OMP_CLAUSE_INTEROP)
+	  ninterop++;
+      if (nappend < ninterop)
+	{
+	  error_at (OMP_CLAUSE_LOCATION (dispatch_interop),
+		    "number of list items in %<interop%> clause (%d) "
+		    "exceeds the number of %<append_args%> items (%d) for "
+		    "%<declare variant%> candidate %qD",
+		    ninterop, nappend, fndecl);
+	  inform (dispatch_append_args
+		  ? EXPR_LOCATION (TREE_PURPOSE (dispatch_append_args))
+		  : DECL_SOURCE_LOCATION (fndecl),
+		  "%<declare variant%> candidate %qD declared here",
+		  fndecl);
+	}
+    }
+  if (dispatch_interop && !dispatch_device_num)
+    {
+      gcc_checking_assert (ninterop > 1);
+      error_at (OMP_CLAUSE_LOCATION (dispatch_interop),
+		"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);
+      tree arg = TYPE_ARG_TYPES (TREE_TYPE (fndecl));
+      /* Copy the first arguments; insert then the interop objects,
+	 and then copy the rest (nargs - nfirst_args) args.  */
+      int i;
+      for (i = 0; i < nfirst_args; i++)
+	{
+	  arg = TREE_CHAIN (arg);
+	  buffer[i] = CALL_EXPR_ARG (expr, i);
+	}
+      int j = nappend;
+      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);
+      for (j = 0; j < nappend; j++)
+	{
+	  /* Fortran permits by-reference or by-value for the dummy arg
+	     and by-value, by-reference, ptr by-reference as actual
+	     argument. Handle this.  */
+	  tree obj = buffer[i + j];  // interop object
+	  tree a2 = TREE_VALUE (arg);  // parameter type
+	  if (POINTER_TYPE_P (TREE_TYPE (obj))
+	      && POINTER_TYPE_P (TREE_TYPE (TREE_TYPE (obj))))
+	    {
+	      tree t = TREE_TYPE (TREE_TYPE (obj));
+	      gcc_checking_assert (INTEGRAL_TYPE_P (TREE_TYPE (t)));
+	      obj = fold_build1 (INDIRECT_REF, t, obj);
+	    }
+	  if (POINTER_TYPE_P (TREE_TYPE (obj))
+	      && INTEGRAL_TYPE_P (a2))
+	    {
+	      tree t = TREE_TYPE (TREE_TYPE (obj));
+	      gcc_checking_assert (INTEGRAL_TYPE_P (t));
+	      obj = fold_build1 (INDIRECT_REF, t, obj);
+	    }
+	  else if (INTEGRAL_TYPE_P (TREE_TYPE (obj))
+		   && POINTER_TYPE_P (a2))
+	    {
+	      gcc_checking_assert (INTEGRAL_TYPE_P (TREE_TYPE (a2)));
+	      obj = build_fold_addr_expr (obj);
+	    }
+	  else if (!INTEGRAL_TYPE_P (a2)
+		   || !INTEGRAL_TYPE_P (TREE_TYPE (obj)))
+	    {
+	      tree t = TREE_TYPE (obj);
+	      gcc_checking_assert (POINTER_TYPE_P (t)
+				   && POINTER_TYPE_P (a2)
+				   && INTEGRAL_TYPE_P (TREE_TYPE (t))
+				   && INTEGRAL_TYPE_P (TREE_TYPE (a2)));
+	    }
+	  buffer[i + j] = obj;
+	  arg = TREE_CHAIN (arg);
+	}
+      i += nappend;
+      for (j = nfirst_args; j < nargs; j++)
+	buffer[i++] = CALL_EXPR_ARG (expr, j);
+      nargs += nappend;
+      tree call = expr;
+      expr = build_call_array_loc (EXPR_LOCATION (expr), TREE_TYPE (call),
+				   CALL_EXPR_FN (call), nargs, buffer);
+
+      /* Copy all CALL_EXPR flags.  */
+      CALL_EXPR_STATIC_CHAIN (expr) = CALL_EXPR_STATIC_CHAIN (call);
+      CALL_EXPR_TAILCALL (expr) = CALL_EXPR_TAILCALL (call);
+      CALL_EXPR_RETURN_SLOT_OPT (expr)
+	= CALL_EXPR_RETURN_SLOT_OPT (call);
+      CALL_FROM_THUNK_P (expr) = CALL_FROM_THUNK_P (call);
+      SET_EXPR_LOCATION (expr, EXPR_LOCATION (call));
+      CALL_EXPR_VA_ARG_PACK (expr) = CALL_EXPR_VA_ARG_PACK (call);
+    }
+
+  /* Nothing to do for adjust_args?  */
+  if (!dispatch_adjust_args_list || !TYPE_ARG_TYPES (TREE_TYPE (fndecl)))
+    return expr;
+
+  for (int i = 0; i < nargs; i++)
+    {
+      tree *arg_p = &CALL_EXPR_ARG (expr, i);
+
+      /* Nothing to do if arg is constant null pointer.  */
+      if (integer_zerop (*arg_p))
+	continue;
+
+      bool need_device_ptr = false;
+      bool need_device_addr = false;
+      for (int need_addr = 0; need_addr <= 1; need_addr++)
+	for (tree arg = (need_addr
+			 ? TREE_VALUE (dispatch_adjust_args_list)
+			 : TREE_PURPOSE (dispatch_adjust_args_list));
+	     arg != NULL; arg = TREE_CHAIN (arg))
+	  {
+	    if (TREE_VALUE (arg)
+		&& TREE_CODE (TREE_VALUE (arg)) == INTEGER_CST
+		&& wi::eq_p (i, wi::to_wide (TREE_VALUE (arg))))
+	      {
+		if (need_addr)
+		  need_device_addr = true;
+		else
+		  need_device_ptr = true;
+		break;
+	      }
+	  }
+
+      if (need_device_ptr || need_device_addr)
+	{
+	  bool is_device_ptr = false;
+	  bool has_device_addr = false;
+
+	  for (tree c = dispatch_clauses; c; c = TREE_CHAIN (c))
+	    {
+	      if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_IS_DEVICE_PTR
+		  || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_HAS_DEVICE_ADDR)
+		{
+		  tree decl1 = DECL_NAME (OMP_CLAUSE_DECL (c));
+		  tree decl2 = tree_strip_nop_conversions (*arg_p);
+		  if (TREE_CODE (decl2) == ADDR_EXPR)
+		    decl2 = TREE_OPERAND (decl2, 0);
+		  if (VAR_P (decl2) || TREE_CODE (decl2) == PARM_DECL)
+		    {
+		      decl2 = DECL_NAME (decl2);
+		      if (decl1 == decl2
+			  && OMP_CLAUSE_CODE (c) == OMP_CLAUSE_IS_DEVICE_PTR)
+			{
+			  if (need_device_addr)
+			    warning_at (OMP_CLAUSE_LOCATION (c),
+					OPT_Wopenmp,
+					"%<is_device_ptr%> for %qD does"
+					" not imply %<has_device_addr%> "
+					"required for %<need_device_addr%>",
+					OMP_CLAUSE_DECL (c));
+			  is_device_ptr = true;
+			  break;
+			}
+		      else if (decl1 == decl2)
+			{
+			  if (need_device_ptr)
+			    warning_at (OMP_CLAUSE_LOCATION (c),
+					OPT_Wopenmp,
+					"%<has_device_addr%> for %qD does"
+					" not imply %<is_device_ptr%> "
+					"required for %<need_device_ptr%>",
+					OMP_CLAUSE_DECL (c));
+			  has_device_addr = true;
+			  break;
+			}
+		    }
+		}
+	    }
+
+	  if ((need_device_ptr && !is_device_ptr)
+	      || (need_device_addr && !has_device_addr))
+	    {
+	      if (dispatch_device_num == NULL_TREE)
+		{
+		  // device_num = omp_get_default_device ()
+		  tree fn
+		    = 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
+		    = build4 (TARGET_EXPR, TREE_TYPE (call),
+			      dispatch_device_num, call, NULL_TREE, NULL_TREE);
+		}
+
+	      // We want to emit the following statement:
+	      //   mapped_arg = omp_get_mapped_ptr (arg,
+	      // 		device_num)
+	      // but arg has to be the actual pointer, not a
+	      // reference or a conversion expression.
+	      tree actual_ptr
+		= ((TREE_CODE (*arg_p) == ADDR_EXPR)
+		   ? TREE_OPERAND (*arg_p, 0)
+		   : *arg_p);
+	      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 (fn, 2, actual_ptr,
+						 dispatch_device_num);
+
+	      if (TREE_CODE (*arg_p) == ADDR_EXPR
+		  || (TREE_CODE (TREE_TYPE (actual_ptr)) == REFERENCE_TYPE))
+		mapped_arg = build_fold_addr_expr (mapped_arg);
+	      else if (TREE_CODE (*arg_p) == NOP_EXPR)
+		mapped_arg = build1 (NOP_EXPR, TREE_TYPE (*arg_p),
+				     mapped_arg);
+	      *arg_p = mapped_arg;
+	    }
+	}
+    }
+  if (dispatch_device_num_init)
+    expr = build2 (COMPOUND_EXPR, TREE_TYPE (expr),
+		   dispatch_device_num_init, expr);
+  return expr;
+}
 
 /* Helper function for gimplify_call_expr: handle "declare variant"
-   resolution and expansion.  Arguments are as for gimplify_call_expr.
-   If *EXPR_P is unchanged, the return value should be ignored and the
-   normal gimplify_call_expr handling should be applied.  Otherwise GS_OK
-   is returned if the new *EXPR_P is something that needs to be further
-   gimplified.  */
+   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.
+   This function may return either the original call or some other
+   expression such as a conditional to select one of multiple calls.
 
-static enum gimplify_status
-gimplify_variant_call_expr (tree *expr_p, gimple_seq *pre_p,
-			    fallback_t fallback)
+   FIXME: this function is written to be independent of gimplifier internals
+   so that it could be moved to omp-general.cc and invoked from the
+   front ends instead, per PR115076.  */
+
+static tree
+expand_variant_call_expr (tree expr, bool want_value, bool pointerize,
+			  bool omp_dispatch_p,
+			  tree dispatch_clauses, location_t dispatch_loc)
 {
   /* If we've already processed this call, stop now.  This can happen
      if the variant call resolves to the original function, or to
      a dynamic conditional that includes the default call to the original
      function.  */
   gcc_assert (omp_resolved_variant_calls != NULL);
-  if (omp_resolved_variant_calls->contains (*expr_p))
-    return GS_OK;
+  if (omp_resolved_variant_calls->contains (expr))
+    return expr;
 
-  tree fndecl = get_callee_fndecl (*expr_p);
-  tree fnptrtype = TREE_TYPE (CALL_EXPR_FN (*expr_p));
-  location_t loc = EXPR_LOCATION (*expr_p);
+  tree fndecl = get_callee_fndecl (expr);
+  tree fnptrtype = TREE_TYPE (CALL_EXPR_FN (expr));
+  location_t loc = EXPR_LOCATION (expr);
   tree construct_context = omp_get_construct_context ();
   vec<struct omp_variant> all_candidates
     = omp_declare_variant_candidates (fndecl, construct_context);
@@ -3921,28 +4223,33 @@ gimplify_variant_call_expr (tree *expr_p, gimple_seq *pre_p,
 	      /* We should only get the original function back as the
 		 default.  */
 	      gcc_assert (!tail);
-	      omp_resolved_variant_calls->add (*expr_p);
-	      tail = *expr_p;
+	      omp_resolved_variant_calls->add (expr);
+	      tail = expr;
 	    }
 	  else
 	    {
 	      /* For the final static selector, we can re-use the old
-		 CALL_EXPR and just replace the function.  Otherwise,
+		 CALL_EXPR and just replace the function, unless it may
+		 need dispatch argument modification.  Otherwise,
 		 make a copy of it.  */
-	      tree thiscall = tail ? unshare_expr (*expr_p) : *expr_p;
+	      tree thiscall = (tail || omp_dispatch_p
+			       ? unshare_expr (expr) : expr);
 	      CALL_EXPR_FN (thiscall) = build1 (ADDR_EXPR, fnptrtype,
 						candidates[i].alternative);
+	      if (omp_dispatch_p)
+		thiscall = modify_call_for_omp_dispatch (thiscall,
+							 dispatch_clauses,
+							 dispatch_loc);
 	      if (!tail)
 		tail = thiscall;
 	      else
-		tail = build3 (COND_EXPR, TREE_TYPE (*expr_p),
+		tail = build3 (COND_EXPR, TREE_TYPE (expr),
 			       omp_dynamic_cond (candidates[i].selector,
 						 find_supercontext ()),
 			       thiscall, tail);
 	    }
 	}
-      *expr_p = tail;
-      return GS_OK;
+      return tail;
     }
 
   /* If we couldn't resolve the variant call now, expand it into a loop using
@@ -3953,31 +4260,22 @@ 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 type = TREE_TYPE (expr);
       tree tmp = NULL_TREE, result = NULL_TREE;
 
       if (want_value)
 	{
-	  /* 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;
-	    }
-
-	  /* 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);
 	    }
+	  else
+	    {
+	      tmp = create_tmp_var (type, "iftmp");
+	      result = tmp;
+	    }
 	}
 
       /* Preprocess the all_candidates array so that the alternative field of
@@ -3989,17 +4287,21 @@ gimplify_variant_call_expr (tree *expr_p, gimple_seq *pre_p,
 	  tree thiscall;
 
 	  /* We need to turn the decl from the candidate into a function
-	     call and possible assignment, gimplify it, and stuff that in
+	     call and possible assignment, and stuff that in
 	     the directive seq of the gomp_variant.  */
 	  if (decl == fndecl)
 	    {
-	      thiscall = *expr_p;
-	      omp_resolved_variant_calls->add (*expr_p);
+	      thiscall = expr;
+	      omp_resolved_variant_calls->add (expr);
 	    }
 	  else
 	    {
-	      thiscall = unshare_expr (*expr_p);
+	      thiscall = unshare_expr (expr);
 	      CALL_EXPR_FN (thiscall) = build1 (ADDR_EXPR, fnptrtype, decl);
+	      if (omp_dispatch_p)
+		thiscall = modify_call_for_omp_dispatch (thiscall,
+							 dispatch_clauses,
+							 dispatch_loc);
 	    }
 	  if (pointerize)
 	    thiscall = build_fold_addr_expr_loc (loc, thiscall);
@@ -4011,14 +4313,42 @@ gimplify_variant_call_expr (tree *expr_p, gimple_seq *pre_p,
       cgraph_node::get (cfun->decl)->has_omp_variant_constructs = 1;
       tree expansion = expand_late_variant_directive (all_candidates,
 						      construct_context);
-      for (tree_stmt_iterator tsi = tsi_start (expansion); !tsi_end_p (tsi);
-	   tsi_delink (&tsi))
-	gimplify_stmt (tsi_stmt_ptr (tsi), pre_p);
-      *expr_p = result;
-      return GS_ALL_DONE;
+      if (result)
+	expansion = build2 (COMPOUND_EXPR, TREE_TYPE (result),
+			    expansion, result);
+      return expansion;
     }
 }
 
+/* Wrapper around expand_variant_call_expr to interface with gimplifier
+   state.  EXPR and OMP_DISPATCH_P are as for expand_variant_call_expr,
+   FALLBACK is used to compute the WANT_VALUE and POINTERIZE arguments.  */
+static tree
+gimplify_variant_call_expr (tree expr, fallback_t fallback,
+			    bool omp_dispatch_p)
+{
+  tree type = TREE_TYPE (expr);
+  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 (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);
+}
+
+
 /* Gimplify the CALL_EXPR node *EXPR_P into the GIMPLE sequence PRE_P.
    WANT_VALUE is true if the result of the call is desired.  */
 
@@ -4030,8 +4360,7 @@ gimplify_call_expr (tree *expr_p, gimple_seq *pre_p, fallback_t fallback)
   enum gimplify_status ret;
   int i, nargs;
   gcall *call;
-  bool builtin_va_start_p = false, omp_dispatch_p = false,
-       variant_substituted_p = false;
+  bool builtin_va_start_p = false, omp_dispatch_p = false;
   location_t loc = EXPR_LOCATION (*expr_p);
 
   gcc_assert (TREE_CODE (*expr_p) == CALL_EXPR);
@@ -4047,8 +4376,13 @@ gimplify_call_expr (tree *expr_p, gimple_seq *pre_p, fallback_t fallback)
       enum internal_fn ifn = CALL_EXPR_IFN (*expr_p);
       if (ifn == IFN_GOMP_DISPATCH)
 	{
-	  gcc_assert (gimplify_omp_ctxp->code == OMP_DISPATCH);
+	  gcc_assert (flag_openmp
+		      && gimplify_omp_ctxp
+		      && gimplify_omp_ctxp->code == OMP_DISPATCH);
 	  *expr_p = CALL_EXPR_ARG (*expr_p, 0);
+	  gcc_assert (TREE_CODE (*expr_p) == CALL_EXPR);
+	  if (! EXPR_HAS_LOCATION (*expr_p))
+	    SET_EXPR_LOCATION (*expr_p, input_location);
 	  omp_dispatch_p = true;
 	}
       else
@@ -4202,7 +4536,7 @@ gimplify_call_expr (tree *expr_p, gimple_seq *pre_p, fallback_t fallback)
   /* Remember the original function pointer type.  */
   fnptrtype = TREE_TYPE (CALL_EXPR_FN (*expr_p));
 
-  /* Handle "declare variant" substitution.  */
+  /* Handle "declare variant" resolution and arglist processing.  */
   if (flag_openmp
       && fndecl
       && cfun
@@ -4212,33 +4546,15 @@ gimplify_call_expr (tree *expr_p, gimple_seq *pre_p, fallback_t fallback)
 			   DECL_ATTRIBUTES (fndecl)))
     {
       tree orig = *expr_p;
-      enum gimplify_status ret
-	= gimplify_variant_call_expr (expr_p, pre_p, fallback);
+      *expr_p = gimplify_variant_call_expr (*expr_p, fallback,
+					    omp_dispatch_p);
+
       /* This may resolve to the same call, or the call expr with just
 	 the function replaced, in which case we should just continue to
 	 gimplify it normally.  Otherwise, if we get something else back,
 	 stop here and re-gimplify the whole replacement expr.  */
       if (*expr_p != orig)
-	{
-	  /* FIXME: The dispatch construct argument-munging code below
-	     breaks when variant substitution returns a conditional
-	     instead of just a (possibly modified) CALL_EXPR.  The "right"
-	     solution is probably to move the argument-munging to
-	     a separate function called from gimplify_variant_call_expr,
-	     where we generate the new calls.  That would also be more
-	     satisfying from an engineering perspective as it would get
-	     the large blob of complicated OpenMP-specific code out of
-	     general function gimplification here.  See PR 118457.  */
-	  if (omp_dispatch_p
-	      && gimplify_omp_ctxp != NULL
-	      && !gimplify_omp_ctxp->in_call_args)
-	    sorry_at (EXPR_LOCATION (orig),
-		      "late or dynamic variant resolution required for "
-		      "call in a %<dispatch%> construct");
-	  return ret;
-	}
-      if (get_callee_fndecl (*expr_p) != fndecl)
-	variant_substituted_p = true;
+	return GS_OK;
     }
 
   /* There is a sequence point before the call, so any side effects in
@@ -4309,199 +4625,6 @@ gimplify_call_expr (tree *expr_p, gimple_seq *pre_p, fallback_t fallback)
      vars there.  */
   bool returns_twice = call_expr_flags (*expr_p) & ECF_RETURNS_TWICE;
 
-  tree dispatch_device_num = NULL_TREE;
-  tree dispatch_adjust_args_list = NULL_TREE;
-  /* OpenMP: Handle the append_args and adjust_args clauses of declare_variant.
-     This is active if enclosed in 'omp dispatch' but only for the outermost
-     function call, which is therefore enclosed in IFN_GOMP_DISPATCH.
-
-     'append_args' cause's interop objects are added after the last regular
-     (nonhidden, nonvariadic) arguments of the variant function.
-     'adjust_args' with need_device_{addr,ptr} converts the pointer target of
-     a pointer from a host to a device address. This uses either the default
-     device or the passed device number, which then sets the default device
-     address.
-
-     FIXME: This code should be moved into an extra function,
-     cf. above + PR118457.  */
-  if (flag_openmp
-      && omp_dispatch_p
-      && gimplify_omp_ctxp != NULL
-      && !gimplify_omp_ctxp->in_call_args
-      && EXPR_P (CALL_EXPR_FN (*expr_p))
-      && DECL_P (TREE_OPERAND (CALL_EXPR_FN (*expr_p), 0)))
-    {
-      tree dispatch_interop = NULL_TREE;
-      tree dispatch_append_args = NULL_TREE;
-      int nfirst_args = 0;
-      if (variant_substituted_p)
-	dispatch_adjust_args_list
-	  = lookup_attribute ("omp declare variant variant args",
-			      DECL_ATTRIBUTES (fndecl));
-      if (dispatch_adjust_args_list)
-	{
-	  dispatch_adjust_args_list = TREE_VALUE (dispatch_adjust_args_list);
-	  dispatch_append_args = TREE_CHAIN (dispatch_adjust_args_list);
-	  if (TREE_PURPOSE (dispatch_adjust_args_list) == NULL_TREE
-	      && TREE_VALUE (dispatch_adjust_args_list) == NULL_TREE)
-	    dispatch_adjust_args_list = NULL_TREE;
-	}
-      if (dispatch_append_args)
-	{
-	  nfirst_args = tree_to_shwi (TREE_PURPOSE (dispatch_append_args));
-	  dispatch_append_args = TREE_VALUE (dispatch_append_args);
-	}
-      dispatch_device_num = omp_find_clause (gimplify_omp_ctxp->clauses,
-					     OMP_CLAUSE_DEVICE);
-      if (dispatch_device_num)
-	dispatch_device_num = OMP_CLAUSE_DEVICE_ID (dispatch_device_num);
-      if (gimplify_omp_ctxp->clauses)
-	dispatch_interop = omp_find_clause (gimplify_omp_ctxp->clauses,
-					    OMP_CLAUSE_INTEROP);
-      /* Already processed?  */
-      if (dispatch_interop
-	  && OMP_CLAUSE_DECL (dispatch_interop) == NULL_TREE)
-	dispatch_interop = dispatch_append_args = NULL_TREE;
-
-      int nappend = 0, ninterop = 0;
-      for (tree t = dispatch_append_args; t; t = TREE_CHAIN (t))
-	nappend++;
-      if (dispatch_interop && !variant_substituted_p)
-	{
-	  error_at (OMP_CLAUSE_LOCATION (dispatch_interop),
-		    "unexpected %<interop%> clause as invoked procedure %qD is "
-		    "not variant substituted", fndecl);
-	  inform (DECL_SOURCE_LOCATION (fndecl),
-		  "%qD declared here", fndecl);
-	  dispatch_interop = NULL_TREE;
-	}
-      else if (dispatch_interop)
-	{
-	  for (tree t = dispatch_interop; t; t = TREE_CHAIN (t))
-	    if (OMP_CLAUSE_CODE (t) == OMP_CLAUSE_INTEROP)
-	      ninterop++;
-	  if (nappend < ninterop)
-	    {
-	      error_at (OMP_CLAUSE_LOCATION (dispatch_interop),
-			"number of list items in %<interop%> clause (%d) "
-			"exceeds the number of %<append_args%> items (%d) for "
-			"%<declare variant%> candidate %qD",
-			ninterop, nappend, fndecl);
-	      inform (dispatch_append_args
-		      ? EXPR_LOCATION (TREE_PURPOSE (dispatch_append_args))
-		      : DECL_SOURCE_LOCATION (fndecl),
-		      "%<declare variant%> candidate %qD declared here",
-		      fndecl);
-	    }
-	}
-      if (dispatch_interop && !dispatch_device_num)
-	{
-	  gcc_checking_assert (ninterop > 1);
-	  error_at (OMP_CLAUSE_LOCATION (dispatch_interop),
-		    "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 (gimplify_omp_ctxp->location,
-		    "required by %<dispatch%> construct");
-	}
-      else if (dispatch_append_args)
-	{
-	  tree *buffer = XALLOCAVEC (tree, nargs + nappend);
-	  tree arg = TYPE_ARG_TYPES (TREE_TYPE (fndecl));
-	  /* Copy the first arguments; insert then the interop objects,
-	     and then copy the rest (nargs - nfirst_args) args.  */
-	  int i;
-	  for (i = 0; i < nfirst_args; i++)
-	    {
-	      arg = TREE_CHAIN (arg);
-	      buffer[i] = CALL_EXPR_ARG (*expr_p, i);
-	    }
-	  int j = nappend;
-	  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);
-	  for (j = 0; j < nappend; j++)
-	    {
-	      /* Fortran permits by-reference or by-value for the dummy arg
-		 and by-value, by-reference, ptr by-reference as actual
-		 argument. Handle this.  */
-	      tree obj = buffer[i + j];  // interop object
-	      tree a2 = TREE_VALUE (arg);  // parameter type
-	      if (POINTER_TYPE_P (TREE_TYPE (obj))
-		  && POINTER_TYPE_P (TREE_TYPE (TREE_TYPE (obj))))
-		{
-		  gcc_checking_assert (INTEGRAL_TYPE_P (
-		    TREE_TYPE (TREE_TYPE (TREE_TYPE (obj)))));
-		  obj = fold_build1 (INDIRECT_REF,
-				     TREE_TYPE (TREE_TYPE (obj)), obj);
-		}
-	      if (POINTER_TYPE_P (TREE_TYPE (obj))
-		  && INTEGRAL_TYPE_P (a2))
-		{
-		  gcc_checking_assert (INTEGRAL_TYPE_P (
-		    TREE_TYPE (TREE_TYPE (obj))));
-		  obj = fold_build1 (INDIRECT_REF,
-				     TREE_TYPE (TREE_TYPE (obj)), obj);
-		}
-	      else if (INTEGRAL_TYPE_P (TREE_TYPE (obj))
-		       && POINTER_TYPE_P (a2))
-		{
-		  gcc_checking_assert (INTEGRAL_TYPE_P (TREE_TYPE (a2)));
-		  obj = build_fold_addr_expr (obj);
-		}
-	      else if (!INTEGRAL_TYPE_P (a2)
-		       || !INTEGRAL_TYPE_P (TREE_TYPE (obj)))
-		{
-		  gcc_checking_assert (
-		    POINTER_TYPE_P (TREE_TYPE (obj))
-		    && POINTER_TYPE_P (a2)
-		    && INTEGRAL_TYPE_P (TREE_TYPE (TREE_TYPE (obj)))
-		    && INTEGRAL_TYPE_P (TREE_TYPE (a2)));
-		}
-	      buffer[i + j] = obj;
-	      arg = TREE_CHAIN (arg);
-	    }
-	  i += nappend;
-	  for (j = nfirst_args; j < nargs; j++)
-	    buffer[i++] = CALL_EXPR_ARG (*expr_p, j);
-	  nargs += nappend;
-	  tree call = *expr_p;
-	  *expr_p = build_call_array_loc (loc, TREE_TYPE (call),
-					  CALL_EXPR_FN (call),
-					  nargs, buffer);
-
-	  /* Copy all CALL_EXPR flags.  */
-	  CALL_EXPR_STATIC_CHAIN (*expr_p) = CALL_EXPR_STATIC_CHAIN (call);
-	  CALL_EXPR_TAILCALL (*expr_p) = CALL_EXPR_TAILCALL (call);
-	  CALL_EXPR_RETURN_SLOT_OPT (*expr_p)
-	    = CALL_EXPR_RETURN_SLOT_OPT (call);
-	  CALL_FROM_THUNK_P (*expr_p) = CALL_FROM_THUNK_P (call);
-	  SET_EXPR_LOCATION (*expr_p, EXPR_LOCATION (call));
-	  CALL_EXPR_VA_ARG_PACK (*expr_p) = CALL_EXPR_VA_ARG_PACK (call);
-	  ret = gimplify_expr (&CALL_EXPR_FN (*expr_p), pre_p, NULL,
-			       is_gimple_call_addr, fb_rvalue);
-	  if (ret == GS_ERROR)
-	    return GS_ERROR;
-
-	  /* Mark as already processed.  */
-	  if (dispatch_interop)
-	    OMP_CLAUSE_DECL (dispatch_interop) = NULL_TREE;
-	  else
-	    {
-	      tree t = build_omp_clause (loc, OMP_CLAUSE_INTEROP);
-	      TREE_CHAIN (t) = gimplify_omp_ctxp->clauses;
-	      gimplify_omp_ctxp->clauses = t;
-	    }
-	}
-    }
 
   /* Gimplify the function arguments.  */
   if (nargs > 0)
@@ -4517,165 +4640,6 @@ gimplify_call_expr (tree *expr_p, gimple_seq *pre_p, fallback_t fallback)
 	  if ((i != 1) || !builtin_va_start_p)
 	    {
 	      tree *arg_p = &CALL_EXPR_ARG (*expr_p, i);
-	      if (dispatch_adjust_args_list && !integer_zerop (*arg_p))
-		{
-		  tree arg_types = TYPE_ARG_TYPES (
-		    TREE_TYPE (TREE_OPERAND (CALL_EXPR_FN (*expr_p), 0)));
-
-		  if (arg_types != NULL_TREE)
-		    {
-		      bool need_device_ptr = false;
-		      bool need_device_addr = false;
-		      for (int need_addr = 0; need_addr <= 1; need_addr++)
-			for (tree arg = need_addr
-					? TREE_VALUE (
-					    dispatch_adjust_args_list)
-					: TREE_PURPOSE (
-					    dispatch_adjust_args_list);
-			     arg != NULL; arg = TREE_CHAIN (arg))
-			  {
-			    if (TREE_VALUE (arg)
-				&& TREE_CODE (TREE_VALUE (arg)) == INTEGER_CST
-				&& wi::eq_p (i, wi::to_wide (TREE_VALUE (arg))))
-			      {
-				if (need_addr)
-				  need_device_addr = true;
-				else
-				  need_device_ptr = true;
-				break;
-			      }
-			  }
-
-		      if (need_device_ptr || need_device_addr)
-			{
-			  bool is_device_ptr = false;
-			  bool has_device_addr = false;
-
-			  for (tree c = gimplify_omp_ctxp->clauses; c;
-			       c = TREE_CHAIN (c))
-			    {
-			      if ((OMP_CLAUSE_CODE (c)
-				   == OMP_CLAUSE_IS_DEVICE_PTR)
-				  || (OMP_CLAUSE_CODE (c)
-				      == OMP_CLAUSE_HAS_DEVICE_ADDR))
-				{
-				  tree decl1 = DECL_NAME (OMP_CLAUSE_DECL (c));
-				  tree decl2
-				    = tree_strip_nop_conversions (*arg_p);
-				  if (TREE_CODE (decl2) == ADDR_EXPR)
-				    decl2 = TREE_OPERAND (decl2, 0);
-				  if (VAR_P (decl2)
-				      || TREE_CODE (decl2) == PARM_DECL)
-				    {
-				      decl2 = DECL_NAME (decl2);
-				      if (decl1 == decl2
-					  && (OMP_CLAUSE_CODE (c)
-					      == OMP_CLAUSE_IS_DEVICE_PTR))
-					{
-					  if (need_device_addr)
-					    warning_at (
-					      OMP_CLAUSE_LOCATION (c),
-					      OPT_Wopenmp,
-					      "%<is_device_ptr%> for %qD does"
-					      " not imply %<has_device_addr%> "
-					      "required for "
-					      "%<need_device_addr%>",
-					       OMP_CLAUSE_DECL (c));
-					  is_device_ptr = true;
-					  break;
-					}
-				      else if (decl1 == decl2)
-					{
-					  if (need_device_ptr)
-					    warning_at (
-					      OMP_CLAUSE_LOCATION (c),
-					      OPT_Wopenmp,
-					      "%<has_device_addr%> for %qD does"
-					      " not imply %<is_device_ptr%> "
-					      "required for "
-					      "%<need_device_ptr%>",
-					      OMP_CLAUSE_DECL (c));
-					  has_device_addr = true;
-					  break;
-					}
-				    }
-				}
-			    }
-
-			  if (variant_substituted_p
-			      && ((need_device_ptr && !is_device_ptr)
-				  || (need_device_addr && !has_device_addr)))
-			    {
-			      if (dispatch_device_num == NULL_TREE)
-				{
-				  // device_num = omp_get_default_device ()
-				  tree fn = builtin_decl_explicit (
-				    BUILT_IN_OMP_GET_DEFAULT_DEVICE);
-				  gcall *call = gimple_build_call (fn, 0);
-				  dispatch_device_num = create_tmp_var (
-				    gimple_call_return_type (call));
-				  gimple_call_set_lhs (call,
-						       dispatch_device_num);
-				  gimplify_seq_add_stmt (pre_p, call);
-				}
-
-			      // We want to emit the following statement:
-			      //   mapped_arg = omp_get_mapped_ptr (arg,
-			      // 		device_num)
-			      // but arg has to be the actual pointer, not a
-			      // reference or a conversion expression.
-			      tree actual_ptr
-				= (TREE_CODE (*arg_p) == ADDR_EXPR)
-				    ? TREE_OPERAND (*arg_p, 0)
-				    : *arg_p;
-			      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);
-				}
-			      gimplify_arg (&actual_ptr, pre_p, loc);
-			      gimplify_arg (&dispatch_device_num, pre_p, loc);
-			      tree fn = builtin_decl_explicit (
-				BUILT_IN_OMP_GET_MAPPED_PTR);
-			      call = gimple_build_call (fn, 2, actual_ptr,
-							dispatch_device_num);
-			      tree mapped_arg = create_tmp_var (
-				gimple_call_return_type (call));
-			      gimple_call_set_lhs (call, mapped_arg);
-			      gimplify_seq_add_stmt (pre_p, call);
-
-			      // gimplify_call_expr might be called several
-			      // times on the same call, which would result in
-			      // duplicated calls to omp_get_default_device and
-			      // omp_get_mapped_ptr. To prevent that, we mark
-			      // already mapped arguments as device pointers.
-			      gcc_checking_assert (gimplify_omp_ctxp->code
-						   == OMP_DISPATCH);
-			      tree c
-				= build_omp_clause (input_location,
-						    OMP_CLAUSE_IS_DEVICE_PTR);
-			      OMP_CLAUSE_DECL (c) = mapped_arg;
-			      OMP_CLAUSE_CHAIN (c) = gimplify_omp_ctxp->clauses;
-			      gimplify_omp_ctxp->clauses = c;
-
-			      if (TREE_CODE (*arg_p) == ADDR_EXPR
-				  || TREE_CODE (TREE_TYPE (actual_ptr))
-				       == REFERENCE_TYPE)
-				mapped_arg = build_fold_addr_expr (mapped_arg);
-			      else if (TREE_CODE (*arg_p) == NOP_EXPR)
-				mapped_arg
-				  = build1 (NOP_EXPR, TREE_TYPE (*arg_p),
-					    mapped_arg);
-			      *arg_p = mapped_arg;
-			    }
-			}
-		    }
-		}
 
 	      if (gimplify_omp_ctxp && gimplify_omp_ctxp->code == OMP_DISPATCH)
 		gimplify_omp_ctxp->in_call_args = true;
@@ -18660,6 +18624,11 @@ gimplify_omp_dispatch (tree *expr_p, gimple_seq *pre_p)
 	    DECL_NAME (base_fndecl));
 	}
 
+      /* We are not actually going to expand the variant call or use
+	 the result of omp_get_dynamic candidates here; only check that
+	 it does not trivially resolve to a call to the base function
+	 so that we can avoid some extra work in building code that's
+	 not needed in that case.  */
       tree construct_context = omp_get_construct_context ();
       vec<struct omp_variant> all_candidates
 	= omp_declare_variant_candidates (base_fndecl, construct_context);
diff --git a/gcc/testsuite/c-c++-common/gomp/adjust-args-6.c b/gcc/testsuite/c-c++-common/gomp/adjust-args-6.c
index 1d5fc4d7ee3..5dc0ab422ad 100644
--- a/gcc/testsuite/c-c++-common/gomp/adjust-args-6.c
+++ b/gcc/testsuite/c-c++-common/gomp/adjust-args-6.c
@@ -13,14 +13,15 @@ void g(int *x);
 void foo(int *y)
 {
   #pragma omp dispatch
-    h(y);
+    h(y);	/* no substitution */
   #pragma omp dispatch
-    f(y);
+    f(y);	/* no substitution */
   #pragma omp dispatch
-    g(y);  /* { dg-bogus "late or dynamic variant resolution" "" { xfail *-*-* } } */
+    g(y);	/* conditional with substitution for f */
 }
 
 /* { dg-final { scan-tree-dump-times "h \\(y\\);" 1 "gimple" } } */
-/* { dg-final { scan-tree-dump-times "f \\(y\\);" 2 "gimple" } } */
-/* { dg-final { scan-tree-dump-times "D\.\[0-9]+ = __builtin_omp_get_mapped_ptr \\(y, D\.\[0-9]+\\);" 1 "gimple" { xfail *-*-* } } } */
-/* { dg-final { scan-tree-dump-times "f \\(D\.\[0-9]+\\);" 1 "gimple" { xfail *-*-* } } } */
+/* { dg-final { scan-tree-dump-times "f \\(y\\);" 1 "gimple" } } */
+/* { dg-final { scan-tree-dump-times "D\.\[0-9]+ = __builtin_omp_get_mapped_ptr \\(y, D\.\[0-9]+\\);" 1 "gimple" } } */
+/* { dg-final { scan-tree-dump-times "f \\(D\.\[0-9]+\\);" 1 "gimple" } } */
+/* { dg-final { scan-tree-dump-times "g \\(y\\);" 1 "gimple" } } */
diff --git a/gcc/testsuite/c-c++-common/gomp/append-args-5.c b/gcc/testsuite/c-c++-common/gomp/append-args-5.c
index 6f57ca86915..37625566f51 100644
--- a/gcc/testsuite/c-c++-common/gomp/append-args-5.c
+++ b/gcc/testsuite/c-c++-common/gomp/append-args-5.c
@@ -16,16 +16,8 @@ typedef enum omp_interop_t __GOMP_UINTPTR_T_ENUM
 } omp_interop_t;
 
 int v1(int, omp_interop_t);
-  /* { dg-note "'v1' declared here" "" { target c } .-1 } */
-  /* { dg-note "'int v1\\(int, omp_interop_t\\)' declared here" "" { target c++ } .-2 } */
-int v1a(int);
-  /* { dg-note "'declare variant' candidate 'v1a' declared here" "" { target c } .-1 } */
-  /* { dg-note "'declare variant' candidate 'int v1a\\(int\\)' declared here" "" { target c++ } .-2 } */
 #pragma omp declare variant(v1) match(construct={dispatch},user={condition(1)}) append_args(interop(targetsync))
-#pragma omp declare variant(v1a) match(user={condition(1)})
 int b1(int);
-  /* { dg-note "'b1' declared here" "" { target c } .-1 } */
-  /* { dg-note "'int b1\\(int\\)' declared here" "" { target c++ } .-2 } */
 
 int v2(int);
 int v2a(int);
@@ -41,21 +33,14 @@ int test (int y1, int y2, int y3, int y4, int num1, int num2, int num3, int num4
 
   #pragma omp dispatch device(num1) interop(obj)
     x1 = v1 (b2 (y1), omp_interop_none);
-      /* { dg-error "unexpected 'interop' clause as invoked procedure 'v1' is not variant substituted" "" { target c } .-2 }  */
-      /* { dg-error "unexpected 'interop' clause as invoked procedure 'int v1\\(int, omp_interop_t\\)' is not variant substituted" "" { target c++ } .-3 }  */
-
 
+  /* No variant substitution because of nocontext */
   #pragma omp dispatch device(num2) nocontext(1) interop(obj)
     x2 = b1 (b2 (y2));
-      /* { dg-error "number of list items in 'interop' clause \\(1\\) exceeds the number of 'append_args' items \\(0\\) for 'declare variant' candidate 'v1a'" "" { target c } .-2 }  */
-      /* { dg-error "number of list items in 'interop' clause \\(1\\) exceeds the number of 'append_args' items \\(0\\) for 'declare variant' candidate 'int v1a\\(int\\)'" "" { target c++ } .-3 }  */
-
 
+  /* No variant substitution because of novariants */
   #pragma omp dispatch device(num2) novariants(1) interop(obj)
     x3 = b1 (b2 (y3));
-      /* { dg-error "unexpected 'interop' clause as invoked procedure 'b1' is not variant substituted" "" { target c } .-2 }  */
-      /* { dg-error "unexpected 'interop' clause as invoked procedure 'int b1\\(int\\)' is not variant substituted" "" { target c++ } .-3 }  */
-
 
   /* OK */
   #pragma omp dispatch device(num4) nocontext(0) interop(obj)
diff --git a/gcc/testsuite/c-c++-common/gomp/append-args-dynamic.c b/gcc/testsuite/c-c++-common/gomp/append-args-dynamic.c
new file mode 100644
index 00000000000..32591cbd0c3
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/gomp/append-args-dynamic.c
@@ -0,0 +1,94 @@
+/* { dg-additional-options "-fdump-tree-gimple" }  */
+
+#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;
+
+typedef enum omp_interop_fr_t
+{
+  omp_ifr_cuda = 1,
+  omp_ifr_cuda_driver = 2,
+  omp_ifr_opencl = 3,
+  omp_ifr_sycl = 4,
+  omp_ifr_hip = 5,
+  omp_ifr_level_zero = 6,
+  omp_ifr_hsa = 7,
+  omp_ifr_last = omp_ifr_hsa
+} omp_interop_fr_t;
+
+
+extern int flag;
+
+void g1(int, const char *, int *, int *, omp_interop_t, omp_interop_t) { }
+void g2(int, const char *, int *, int *, omp_interop_t, omp_interop_t) { }
+#pragma omp declare variant(g1) \
+    match(construct={dispatch}, user={condition(flag==1)}) \
+    append_args(interop(target,prefer_type( {fr("cuda") }, {fr(omp_ifr_hsa)} , {attr("ompx_a") } , {fr(omp_ifr_hip) }), targetsync), \
+               interop(targetsync, prefer_type("cuda", "hsa"))) \
+    adjust_args(need_device_ptr : y, k)
+#pragma omp declare variant(g2) \
+    match(construct={dispatch}, user={condition(flag==2)}) \
+    append_args(interop(target,prefer_type( {fr("cuda") }, {fr(omp_ifr_hsa)} , {attr("ompx_a") } , {fr(omp_ifr_hip) }), targetsync), \
+               interop(targetsync, prefer_type("cuda", "hsa"))) \
+    adjust_args(need_device_ptr : y)
+void f(int x, const char *y, int *, int *k) { }
+
+
+void gvar1(int, const char *, int *, int *, omp_interop_t, omp_interop_t, ...) { }
+void gvar2(int, const char *, int *, int *, omp_interop_t, omp_interop_t, ...) { }
+#pragma omp declare variant(gvar1) \
+   match(construct={dispatch}, user={condition(flag==3)}) \
+   append_args(interop(target,prefer_type( {fr("cuda") }, {fr(omp_ifr_hsa)} , {attr("ompx_a") } , {fr(omp_ifr_hip) }), targetsync), \
+               interop(targetsync, prefer_type("cuda", "hsa"))) \
+   adjust_args(need_device_ptr : y, k)
+#pragma omp declare variant(gvar2) \
+   match(construct={dispatch}, user={condition(flag==4)}) \
+   append_args(interop(target,prefer_type( {fr("cuda") }, {fr(omp_ifr_hsa)} , {attr("ompx_a") } , {fr(omp_ifr_hip) }), targetsync), \
+               interop(targetsync, prefer_type("cuda", "hsa"))) \
+   adjust_args(need_device_ptr : y)
+void fvar(int x, const char *y, int *, int *k, ...) { }
+
+void foo(const char *cp1, const char *cp2, int *a, int *b, int *c)
+{
+  omp_interop_t obj1, obj2, obj3, obj4;
+  obj1 = obj2 = obj3 = obj4 = omp_interop_none;
+
+  #pragma omp dispatch device(5) interop(obj1,obj2) is_device_ptr(cp1)
+     f(3, cp1, a, b);
+
+  #pragma omp dispatch device(4) interop(obj3,obj4) is_device_ptr(a,b,c)
+     fvar(99, cp2, a, b, c, a, b, c, a, b, c);
+}
+
+/* Since the selectors are dynamic, there must be calls to all the variants as
+   well as the base functions.  */
+/* { dg-final { scan-tree-dump "f \\(3, cp1, a, b\\)" "gimple" } } */
+/* { dg-final { scan-tree-dump "g1 \\(3, cp1, a, D\.\[0-9\]+, obj1, obj2\\)" "gimple" } } */
+/* { dg-final { scan-tree-dump "g2 \\(3, cp1, a, b, obj1, obj2\\)" "gimple" } } */
+/* { dg-final { scan-tree-dump "fvar \\(99, cp2, a, b, c, a, b, c, a, b, c\\)" "gimple" } } */
+/* { dg-final { scan-tree-dump "gvar1 \\(99, D\.\[0-9\]+, a, b, obj3, obj4, c, a, b, c, a, b, c\\)" "gimple" } } */
+/* { dg-final { scan-tree-dump "gvar2 \\(99, D\.\[0-9\]+, a, b, obj3, obj4, c, a, b, c, a, b, c\\)" "gimple" } } */
+
+/* Check that the condition tests appear in the output, too.  */
+/* { dg-final { scan-tree-dump "if \\(flag.\[0-9\]+ == 1\\)" "gimple" } } */
+/* { dg-final { scan-tree-dump "if \\(flag.\[0-9\]+ == 2\\)" "gimple" } } */
+/* { dg-final { scan-tree-dump "if \\(flag.\[0-9\]+ == 3\\)" "gimple" } } */
+/* { dg-final { scan-tree-dump "if \\(flag.\[0-9\]+ == 4\\)" "gimple" } } */
+
+/* There should be one call to map the pointer b for the call to f's variant
+   g1; g2 doesn't have a need_device_ptr on this parameter.  */
+/* { dg-final { scan-tree-dump-times "D\.\[0-9\]+ = __builtin_omp_get_mapped_ptr \\(b," 1 "gimple" } }  */
+
+/* Both variants for fvar need to map pointer cp2.  */
+/* { dg-final { scan-tree-dump-times "D\.\[0-9\]+ = __builtin_omp_get_mapped_ptr \\(cp2," 2 "gimple" } }  */
+
+
+
diff --git a/gcc/testsuite/c-c++-common/gomp/dispatch-11.c b/gcc/testsuite/c-c++-common/gomp/dispatch-11.c
index 118dbd2663e..e59985a5691 100644
--- a/gcc/testsuite/c-c++-common/gomp/dispatch-11.c
+++ b/gcc/testsuite/c-c++-common/gomp/dispatch-11.c
@@ -19,14 +19,10 @@ typedef enum omp_interop_t __GOMP_UINTPTR_T_ENUM
 float repl1();
 #pragma omp declare variant(repl1) match(construct={dispatch})
 float base1();
-/* { dg-note "'base1' declared here" "" { target c } .-1 }  */
-/* { dg-note "'float base1\\(\\)' declared here" "" { target c++ } .-2 }  */
 
 void repl2(int *, int *);
 #pragma omp declare variant(repl2) match(construct={dispatch}) adjust_args(need_device_ptr : y)
 void base2(int *x, int *y);
-/* { dg-note "'base2' declared here" "" { target c } .-1 }  */
-/* { dg-note "'void base2\\(int\\*, int\\*\\)' declared here" "" { target c++ } .-2 }  */
 
 void repl3(int *, int *, omp_interop_t);
 #pragma omp declare variant(repl3) match(construct={dispatch}) adjust_args(need_device_ptr : y) append_args(interop(target))
@@ -46,8 +42,6 @@ dupl (int *a, int *b)
 
   #pragma omp dispatch interop ( obj1) nocontext(1) interop (obj2 )  device(2)/* { dg-error "too many 'interop' clauses" }  */
     base2 (a, b);
-  /* { dg-error "unexpected 'interop' clause as invoked procedure 'base2' is not variant substituted" "" { target c } .-2 } */
-  /* { dg-error "unexpected 'interop' clause as invoked procedure 'void base2\\(int\\*, int\\*\\)' is not variant substituted" "" { target c++ } .-3 } */
   return x;
 }
 
@@ -55,12 +49,12 @@ dupl (int *a, int *b)
 /* { dg-note "'declare variant' candidate 'float repl1\\(\\)' declared here" "" { target c++ } 19 } */
 
 
-/* { dg-note "'declare variant' candidate 'repl2' declared here" ""                          { target c }   25 } */
-/* { dg-note "'declare variant' candidate 'void repl2\\(int\\*, int\\*\\)' declared here" "" { target c++ } 25 } */
+/* { dg-note "'declare variant' candidate 'repl2' declared here" ""                          { target c }   23 } */
+/* { dg-note "'declare variant' candidate 'void repl2\\(int\\*, int\\*\\)' declared here" "" { target c++ } 23 } */
 
 
-/* { dg-note "'declare variant' candidate 'repl3' declared here" ""                                         { target c }   32 } */
-/* { dg-note "'declare variant' candidate 'void repl3\\(int\\*, int\\*, omp_interop_t\\)' declared here" "" { target c++ } 32 } */
+/* { dg-note "'declare variant' candidate 'repl3' declared here" ""                                         { target c }   28 } */
+/* { dg-note "'declare variant' candidate 'void repl3\\(int\\*, int\\*, omp_interop_t\\)' declared here" "" { target c++ } 28 } */
 
 float
 test (int *a, int *b)
@@ -80,8 +74,6 @@ test (int *a, int *b)
 
   #pragma omp dispatch novariants(1) interop(obj2, obj1) device(0)
     y = base1 ();
-  /* { dg-error "unexpected 'interop' clause as invoked procedure 'base1' is not variant substituted" "" { target c } .-2 } */
-  /* { dg-error "unexpected 'interop' clause as invoked procedure 'float base1\\(\\)' is not variant substituted" "" { target c++ } .-3 } */
 
   #pragma omp dispatch interop(obj2, obj1) device(3)
     base2 (a, b);
@@ -90,8 +82,6 @@ test (int *a, int *b)
 
   #pragma omp dispatch interop(obj2) nocontext(1)
     base2 (a, b);
-  /* { dg-error "unexpected 'interop' clause as invoked procedure 'base2' is not variant substituted" "" { target c } .-2 } */
-  /* { dg-error "unexpected 'interop' clause as invoked procedure 'void base2\\(int\\*, int\\*\\)' is not variant substituted" "" { target c++ } .-3 } */
 
   #pragma omp dispatch interop(obj3, obj2) device(2)
     base3 (a, b);
@@ -101,8 +91,8 @@ test (int *a, int *b)
 
   #pragma omp dispatch interop(obj3)
     base3 (a, b);
-  /* { dg-message "sorry, unimplemented: 'append_args' clause not yet supported for 'repl3'" "" { target c } 32 }  */
-  /* { dg-message "sorry, unimplemented: 'append_args' clause not yet supported for 'void repl3\\(int\\*, int\\*, omp_interop_t\\)'" "" { target c++ } 32 }  */
+  /* { 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/gfortran.dg/gomp/dispatch-11.f90 b/gcc/testsuite/gfortran.dg/gomp/dispatch-11.f90
index 2a909a3ca73..cc8b5252764 100644
--- a/gcc/testsuite/gfortran.dg/gomp/dispatch-11.f90
+++ b/gcc/testsuite/gfortran.dg/gomp/dispatch-11.f90
@@ -14,7 +14,6 @@ module m
     real function repl1(); end  ! { dg-note "'declare variant' candidate 'repl1' declared here" }
 
     real function base1()
-! { dg-note "'base1' declared here" "" { target *-*-* } .-1 }
       !$omp declare variant(repl1) match(construct={dispatch})
     end
 
@@ -23,7 +22,6 @@ module m
       type(c_ptr), value :: x1, x2
     end
     subroutine base2 (x, y)
-! { dg-note "'base2' declared here" "" { target *-*-* } .-1 }
       import
       type(c_ptr), value :: x, y
       !$omp declare variant(repl2) match(construct={dispatch}) adjust_args(need_device_ptr : y)
@@ -43,7 +41,6 @@ real function dupl (a, b)
 
   !$omp dispatch device(9) interop ( obj1, obj2) nocontext(.true.)
     call base2 (a, b)
-  ! { dg-error "unexpected 'interop' clause as invoked procedure 'base2' is not variant substituted" "" { target *-*-* } .-1 }
   dupl = x
 end
 
@@ -62,7 +59,6 @@ real function test (a, b)
 
   !$omp dispatch novariants(.true.) interop(obj2, obj1) device(0)
     y = base1 ()
-  ! { dg-error "unexpected 'interop' clause as invoked procedure 'base1' is not variant substituted" "" { target *-*-* } .-1 }
 
   !$omp dispatch interop(obj2, obj1) device(3)
     call base2 (a, b)
@@ -70,7 +66,6 @@ real function test (a, b)
 
   !$omp dispatch interop(obj2) nocontext(.true.)
     call base2 (a, b)
-  ! { dg-error "unexpected 'interop' clause as invoked procedure 'base2' is not variant substituted" "" { target *-*-* } .-1 }
   test = x + y
 end
 end module
-- 
2.34.1

Reply via email to