public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [PATCH 0/5, OpenACC] Add support for Fortran optional arguments in OpenACC
@ 2019-07-12 11:35 ` Kwok Cheung Yeung
  2019-07-12 11:36   ` [PATCH 1/5, OpenACC] Allow NULL as an argument to OpenACC 2.6 directives Kwok Cheung Yeung
                     ` (4 more replies)
  0 siblings, 5 replies; 65+ messages in thread
From: Kwok Cheung Yeung @ 2019-07-12 11:35 UTC (permalink / raw)
  To: gcc-patches, fortran, jakub; +Cc: thomas

This patchset allows the use of Fortran optional arguments in OpenACC 
programs in accordance with section 2.17 of the OpenACC 2.6 specification.

These patches were originally posted at 
https://gcc.gnu.org/ml/gcc-patches/2019-01/msg01750.html for the OG8 
branch. This version is targeted at trunk.

Tested on x86_64 with offloading to a Nvidia Tesla K20c card.

Okay to apply to trunk?

Thanks

Kwok

^ permalink raw reply	[flat|nested] 65+ messages in thread

* [PATCH 1/5, OpenACC] Allow NULL as an argument to OpenACC 2.6 directives
  2019-07-12 11:35 ` [PATCH 0/5, OpenACC] Add support for Fortran optional arguments in OpenACC Kwok Cheung Yeung
@ 2019-07-12 11:36   ` Kwok Cheung Yeung
  2019-11-29 14:42     ` [PR92726] OpenACC: 'NULL'-in -> no-op, and/or 'NULL'-out (was: [PATCH 1/5, OpenACC] Allow NULL as an argument to OpenACC 2.6 directives) Thomas Schwinge
  2019-07-12 11:37   ` [PATCH 2/5, OpenACC] Support Fortran optional arguments in the firstprivate clause Kwok Cheung Yeung
                     ` (3 subsequent siblings)
  4 siblings, 1 reply; 65+ messages in thread
From: Kwok Cheung Yeung @ 2019-07-12 11:36 UTC (permalink / raw)
  To: gcc-patches, fortran, jakub; +Cc: thomas

Fortran pass-by-reference optional arguments behave much like normal 
Fortran arguments when lowered to GENERIC/GIMPLE, except they can be 
null (representing a non-present argument).

Some parts of libgomp (those dealing with updating mappings) currently 
do not expect to take a null address and fail. These need to be changed 
to deal with the null appropriately, by turning the operation into a 
no-op (as you never need to update a non-present argument).

	libgomp/
	* oacc-mem.c (update_dev_host): Return early if the host address
	is NULL.
	(gomp_acc_insert_pointer): Likewise.
	* testsuite/libgomp.oacc-c-c++-common/lib-43.c: Remove.
	* testsuite/libgomp.oacc-c-c++-common/lib-47.c: Likewise.
---
  libgomp/oacc-mem.c                                 |  9 ++++
  .../testsuite/libgomp.oacc-c-c++-common/lib-43.c   | 51 
----------------------
  .../testsuite/libgomp.oacc-c-c++-common/lib-47.c   | 49 
---------------------
  3 files changed, 9 insertions(+), 100 deletions(-)
  delete mode 100644 libgomp/testsuite/libgomp.oacc-c-c++-common/lib-43.c
  delete mode 100644 libgomp/testsuite/libgomp.oacc-c-c++-common/lib-47.c

diff --git a/libgomp/oacc-mem.c b/libgomp/oacc-mem.c
index 2f27100..8cc5120 100644
--- a/libgomp/oacc-mem.c
+++ b/libgomp/oacc-mem.c
@@ -831,6 +831,12 @@ update_dev_host (int is_dev, void *h, size_t s, int 
async)
    if (acc_dev->capabilities & GOMP_OFFLOAD_CAP_SHARED_MEM)
      return;

+  /* Fortran optional arguments that are non-present result in a
+     null host address here.  This can safely be ignored as it is
+     not possible to 'update' a non-present optional argument.  */
+  if (h == NULL)
+    return;
+
    acc_prof_info prof_info;
    acc_api_info api_info;
    bool profiling_p = GOACC_PROFILING_SETUP_P (thr, &prof_info, &api_info);
@@ -901,6 +907,9 @@ gomp_acc_insert_pointer (size_t mapnum, void 
**hostaddrs, size_t *sizes,
    struct goacc_thread *thr = goacc_thread ();
    struct gomp_device_descr *acc_dev = thr->dev;

+  if (*hostaddrs == NULL)
+    return;
+
    if (acc_is_present (*hostaddrs, *sizes))
      {
        splay_tree_key n;
diff --git a/libgomp/testsuite/libgomp.oacc-c-c++-common/lib-43.c 
b/libgomp/testsuite/libgomp.oacc-c-c++-common/lib-43.c
deleted file mode 100644
index 5db2912..0000000
--- a/libgomp/testsuite/libgomp.oacc-c-c++-common/lib-43.c
+++ /dev/null
@@ -1,51 +0,0 @@
-/* Exercise acc_update_device with a NULL data address on nvidia 
targets.  */
-
-/* { dg-do run { target openacc_nvidia_accel_selected } } */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <openacc.h>
-
-int
-main (int argc, char **argv)
-{
-  const int N = 256;
-  int i;
-  unsigned char *h;
-  void *d;
-
-  h = (unsigned char *) malloc (N);
-
-  for (i = 0; i < N; i++)
-    {
-      h[i] = i;
-    }
-
-  d = acc_copyin (h, N);
-  if (!d)
-    abort ();
-
-  for (i = 0; i < N; i++)
-    {
-      h[i] = 0xab;
-    }
-
-  fprintf (stderr, "CheCKpOInT\n");
-  acc_update_device (0, N);
-
-  acc_copyout (h, N);
-
-  for (i = 0; i < N; i++)
-    {
-      if (h[i] != 0xab)
-	abort ();
-    }
-
-  free (h);
-
-  return 0;
-}
-
-/* { dg-output "CheCKpOInT(\n|\r\n|\r).*" } */
-/* { dg-output "\\\[\[^\n\r]*,256\\\] is not mapped" } */
-/* { dg-shouldfail "" } */
diff --git a/libgomp/testsuite/libgomp.oacc-c-c++-common/lib-47.c 
b/libgomp/testsuite/libgomp.oacc-c-c++-common/lib-47.c
deleted file mode 100644
index c214042..0000000
--- a/libgomp/testsuite/libgomp.oacc-c-c++-common/lib-47.c
+++ /dev/null
@@ -1,49 +0,0 @@
-/* Exercise acc_update_self with a NULL data mapping on nvidia targets.  */
-
-/* { dg-do run { target openacc_nvidia_accel_selected } } */
-
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-#include <openacc.h>
-
-int
-main (int argc, char **argv)
-{
-  const int N = 256;
-  int i;
-  unsigned char *h;
-  void *d;
-
-  h = (unsigned char *) malloc (N);
-
-  for (i = 0; i < N; i++)
-    {
-      h[i] = i;
-    }
-
-  d = acc_copyin (h, N);
-  if (!d)
-    abort ();
-
-  memset (&h[0], 0, N);
-
-  fprintf (stderr, "CheCKpOInT\n");
-  acc_update_self (0, N);
-
-  for (i = 0; i < N; i++)
-    {
-      if (h[i] != i)
-	abort ();
-    }
-
-  acc_delete (h, N);
-
-  free (h);
-
-  return 0;
-}
-
-/* { dg-output "CheCKpOInT(\n|\r\n|\r).*" } */
-/* { dg-output "\\\[\[^\n\r]*,256\\\] is not mapped" } */
-/* { dg-shouldfail "" } */
-- 
2.8.1

^ permalink raw reply	[flat|nested] 65+ messages in thread

* [PATCH 2/5, OpenACC] Support Fortran optional arguments in the firstprivate clause
  2019-07-12 11:35 ` [PATCH 0/5, OpenACC] Add support for Fortran optional arguments in OpenACC Kwok Cheung Yeung
  2019-07-12 11:36   ` [PATCH 1/5, OpenACC] Allow NULL as an argument to OpenACC 2.6 directives Kwok Cheung Yeung
@ 2019-07-12 11:37   ` Kwok Cheung Yeung
  2019-07-12 11:42     ` Jakub Jelinek
  2019-07-12 11:39   ` [PATCH 4/5, OpenACC] Allow optional arguments to be used in the use_device OpenACC clause Kwok Cheung Yeung
                     ` (2 subsequent siblings)
  4 siblings, 1 reply; 65+ messages in thread
From: Kwok Cheung Yeung @ 2019-07-12 11:37 UTC (permalink / raw)
  To: gcc-patches, fortran, jakub; +Cc: thomas

Reference types used by Fortran often need to be treated specially in 
the OACC lowering to deal with the referenced object as well as the 
reference itself. However, as optional arguments can be null, they are 
pointer types rather than reference types, so the code to detect these 
situations needs to be updated.

	gcc/
	* omp-general.c (omp_is_optional_argument): New.
	* omp-general.h (omp_is_optional_argument): New.
	* omp-low.c (lower_omp_target): Use size of referenced object when
	optional argument used as argument to firstprivate.  Create temporary
	for received value and take the address for new_var if the original
	variable was an optional argument.
---
  gcc/omp-general.c | 14 ++++++++++++++
  gcc/omp-general.h |  1 +
  gcc/omp-low.c     |  8 +++++---
  3 files changed, 20 insertions(+), 3 deletions(-)

diff --git a/gcc/omp-general.c b/gcc/omp-general.c
index 8086f9a..e5173b8 100644
--- a/gcc/omp-general.c
+++ b/gcc/omp-general.c
@@ -48,6 +48,20 @@ omp_find_clause (tree clauses, enum omp_clause_code kind)
    return NULL_TREE;
  }

+/* Return true if DECL is a Fortran optional argument.  */
+
+bool
+omp_is_optional_argument (tree decl)
+{
+  /* A passed-by-reference Fortran optional argument is similar to
+     a normal argument, but since it can be null the type is a
+     POINTER_TYPE rather than a REFERENCE_TYPE.  */
+  return lang_GNU_Fortran ()
+        && TREE_CODE (decl) == PARM_DECL
+        && DECL_BY_REFERENCE (decl)
+	 && TREE_CODE (TREE_TYPE (decl)) == POINTER_TYPE;
+}
+
  /* Return true if DECL is a reference type.  */

  bool
diff --git a/gcc/omp-general.h b/gcc/omp-general.h
index 80d42af..bbaa7b1 100644
--- a/gcc/omp-general.h
+++ b/gcc/omp-general.h
@@ -73,6 +73,7 @@ struct omp_for_data
  #define OACC_FN_ATTRIB "oacc function"

  extern tree omp_find_clause (tree clauses, enum omp_clause_code kind);
+extern bool omp_is_optional_argument (tree decl);
  extern bool omp_is_reference (tree decl);
  extern void omp_adjust_for_condition (location_t loc, enum tree_code 
*cond_code,
  				      tree *n2, tree v, tree step);
diff --git a/gcc/omp-low.c b/gcc/omp-low.c
index a855c5b..625df1e 100644
--- a/gcc/omp-low.c
+++ b/gcc/omp-low.c
@@ -11172,8 +11172,9 @@ lower_omp_target (gimple_stmt_iterator *gsi_p, 
omp_context *ctx)
  	    if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_FIRSTPRIVATE)
  	      {
  		gcc_assert (is_gimple_omp_oacc (ctx->stmt));
-		if (omp_is_reference (new_var)
-		    && TREE_CODE (TREE_TYPE (new_var)) != POINTER_TYPE)
+		if ((omp_is_reference (new_var)
+		     && TREE_CODE (TREE_TYPE (new_var)) != POINTER_TYPE)
+		    || omp_is_optional_argument (var))
  		  {
  		    /* Create a local object to hold the instance
  		       value.  */
@@ -11461,7 +11462,8 @@ lower_omp_target (gimple_stmt_iterator *gsi_p, 
omp_context *ctx)
  	      {
  		gcc_checking_assert (is_gimple_omp_oacc (ctx->stmt));
  		s = TREE_TYPE (ovar);
-		if (TREE_CODE (s) == REFERENCE_TYPE)
+		if (TREE_CODE (s) == REFERENCE_TYPE
+		    || omp_is_optional_argument (ovar))
  		  s = TREE_TYPE (s);
  		s = TYPE_SIZE_UNIT (s);
  	      }
-- 
2.8.1


^ permalink raw reply	[flat|nested] 65+ messages in thread

* [PATCH 4/5, OpenACC] Allow optional arguments to be used in the use_device OpenACC clause
  2019-07-12 11:35 ` [PATCH 0/5, OpenACC] Add support for Fortran optional arguments in OpenACC Kwok Cheung Yeung
  2019-07-12 11:36   ` [PATCH 1/5, OpenACC] Allow NULL as an argument to OpenACC 2.6 directives Kwok Cheung Yeung
  2019-07-12 11:37   ` [PATCH 2/5, OpenACC] Support Fortran optional arguments in the firstprivate clause Kwok Cheung Yeung
@ 2019-07-12 11:39   ` Kwok Cheung Yeung
  2019-07-29 22:42     ` Kwok Cheung Yeung
  2019-07-12 11:39   ` [PATCH 3/5, OpenACC] Add support for allocatable arrays as optional arguments Kwok Cheung Yeung
  2019-07-12 11:41   ` [PATCH 5/5, OpenACC] Add tests for Fortran optional arguments in OpenACC 2.6 Kwok Cheung Yeung
  4 siblings, 1 reply; 65+ messages in thread
From: Kwok Cheung Yeung @ 2019-07-12 11:39 UTC (permalink / raw)
  To: gcc-patches, fortran, jakub; +Cc: thomas

This patch fixes a similar situation that occurs with the use_device 
clause, where the lowering would result in a null dereference if applied 
to a non-present optional argument. This patch builds a conditional 
check that skips the dereference if the argument is non-present, and 
ensures that optional arguments are treated like references.

	gcc/
	* omp-low.c (lower_omp_target): For use_device clauses, generate
	conditional statements to treat Fortran optional arguments like
	references if non-null, or propogate null arguments into offloaded
	code otherwise.
---
  gcc/omp-low.c | 77 
+++++++++++++++++++++++++++++++++++++++++++++++++++++++----
  1 file changed, 73 insertions(+), 4 deletions(-)

diff --git a/gcc/omp-low.c b/gcc/omp-low.c
index 625df1e..2dfeca5 100644
--- a/gcc/omp-low.c
+++ b/gcc/omp-low.c
@@ -11635,18 +11635,51 @@ lower_omp_target (gimple_stmt_iterator *gsi_p, 
omp_context *ctx)
  	      tkind = GOMP_MAP_FIRSTPRIVATE_INT;
  	    type = TREE_TYPE (ovar);
  	    if (TREE_CODE (type) == ARRAY_TYPE)
-	      var = build_fold_addr_expr (var);
+	      {
+		var = build_fold_addr_expr (var);
+		gimplify_assign (x, var, &ilist);
+	      }
  	    else
  	      {
-		if (omp_is_reference (ovar))
+		tree opt_arg_label;
+		bool optional_arg_p = omp_is_optional_argument (ovar);
+
+		if (optional_arg_p)
+		  {
+		    tree null_label
+		      = create_artificial_label (UNKNOWN_LOCATION);
+		    tree notnull_label
+		      = create_artificial_label (UNKNOWN_LOCATION);
+		    opt_arg_label
+		      = create_artificial_label (UNKNOWN_LOCATION);
+		    tree new_x = copy_node (x);
+		    gcond *cond = gimple_build_cond (EQ_EXPR, ovar,
+						     null_pointer_node,
+						     null_label,
+						     notnull_label);
+		    gimple_seq_add_stmt (&ilist, cond);
+		    gimple_seq_add_stmt (&ilist,
+					 gimple_build_label (null_label));
+		    gimplify_assign (new_x, null_pointer_node, &ilist);
+		    gimple_seq_add_stmt (&ilist,
+					 gimple_build_goto (opt_arg_label));
+		    gimple_seq_add_stmt (&ilist,
+					 gimple_build_label (notnull_label));
+		  }
+
+		if (omp_is_reference (ovar) || optional_arg_p)
  		  {
  		    type = TREE_TYPE (type);
  		    if (TREE_CODE (type) != ARRAY_TYPE)
  		      var = build_simple_mem_ref (var);
  		    var = fold_convert (TREE_TYPE (x), var);
  		  }
+
+		gimplify_assign (x, var, &ilist);
+		if (optional_arg_p)
+		  gimple_seq_add_stmt (&ilist,
+				       gimple_build_label (opt_arg_label));
  	      }
-	    gimplify_assign (x, var, &ilist);
  	    s = size_int (0);
  	    purpose = size_int (map_idx++);
  	    CONSTRUCTOR_APPEND_ELT (vsize, purpose, s);
@@ -11828,11 +11861,43 @@ lower_omp_target (gimple_stmt_iterator *gsi_p, 
omp_context *ctx)
  	      {
  		tree type = TREE_TYPE (var);
  		tree new_var = lookup_decl (var, ctx);
-		if (omp_is_reference (var))
+		tree opt_arg_label = NULL_TREE;
+
+		if (omp_is_reference (var) || omp_is_optional_argument (var))
  		  {
  		    type = TREE_TYPE (type);
  		    if (TREE_CODE (type) != ARRAY_TYPE)
  		      {
+			if (omp_is_optional_argument (var))
+			  {
+			    tree null_label
+			      = create_artificial_label (UNKNOWN_LOCATION);
+			    tree notnull_label
+			      = create_artificial_label (UNKNOWN_LOCATION);
+			    opt_arg_label
+			      = create_artificial_label (UNKNOWN_LOCATION);
+			    glabel *null_glabel
+			      = gimple_build_label (null_label);
+			    glabel *notnull_glabel
+			      = gimple_build_label (notnull_label);
+			    ggoto *opt_arg_ggoto
+			      = gimple_build_goto (opt_arg_label);
+			    gcond *cond;
+
+			    gimplify_expr (&x, &new_body, NULL, is_gimple_val,
+					   fb_rvalue);
+			    cond = gimple_build_cond (EQ_EXPR, x,
+						      null_pointer_node,
+						      null_label,
+						      notnull_label);
+			    gimple_seq_add_stmt (&new_body, cond);
+			    gimple_seq_add_stmt (&new_body, null_glabel);
+			    gimplify_assign (new_var, null_pointer_node,
+					     &new_body);
+			    gimple_seq_add_stmt (&new_body, opt_arg_ggoto);
+			    gimple_seq_add_stmt (&new_body, notnull_glabel);
+			  }
+
  			tree v = create_tmp_var_raw (type, get_name (var));
  			gimple_add_tmp_var (v);
  			TREE_ADDRESSABLE (v) = 1;
@@ -11849,6 +11914,10 @@ lower_omp_target (gimple_stmt_iterator *gsi_p, 
omp_context *ctx)
  		gimplify_expr (&x, &new_body, NULL, is_gimple_val, fb_rvalue);
  		gimple_seq_add_stmt (&new_body,
  				     gimple_build_assign (new_var, x));
+
+		if (opt_arg_label != NULL_TREE)
+		  gimple_seq_add_stmt (&new_body,
+				       gimple_build_label (opt_arg_label));
  	      }
  	    break;
  	  }
-- 
2.8.1

^ permalink raw reply	[flat|nested] 65+ messages in thread

* [PATCH 3/5, OpenACC] Add support for allocatable arrays as optional arguments
  2019-07-12 11:35 ` [PATCH 0/5, OpenACC] Add support for Fortran optional arguments in OpenACC Kwok Cheung Yeung
                     ` (2 preceding siblings ...)
  2019-07-12 11:39   ` [PATCH 4/5, OpenACC] Allow optional arguments to be used in the use_device OpenACC clause Kwok Cheung Yeung
@ 2019-07-12 11:39   ` Kwok Cheung Yeung
  2019-07-12 11:41   ` [PATCH 5/5, OpenACC] Add tests for Fortran optional arguments in OpenACC 2.6 Kwok Cheung Yeung
  4 siblings, 0 replies; 65+ messages in thread
From: Kwok Cheung Yeung @ 2019-07-12 11:39 UTC (permalink / raw)
  To: gcc-patches, fortran, jakub; +Cc: thomas

This patch allows allocatable arrays passed as Fortran optional
arguments to be used in OpenACC. The GIMPLE code generated by the 
current lowering unconditionally attempts to access fields within the 
structure representing the array, resulting in a null dereference if the 
array is non-present.

This patch generates extra code to test if the argument is null.
If so, it sets the size of the array contents to zero, and the
pointers to data to null. This avoids the null dereferences, prevents 
libgomp from trying to copy non-existant data, and preserves the null 
pointer used by PRESENT to detect non-present arguments.

	gcc/fortran/
	* trans-openmp.c (gfc_build_conditional_assign): New.
	(gfc_build_conditional_assign_expr): New.
	(gfc_omp_finish_clause): Add conditionals to set the clause
	declaration to null and size to zero if the declaration is a
	non-present optional argument.
	(gfc_trans_omp_clauses): Likewise.
---
  gcc/fortran/trans-openmp.c | 164 
++++++++++++++++++++++++++++++++++++++-------
  1 file changed, 138 insertions(+), 26 deletions(-)

diff --git a/gcc/fortran/trans-openmp.c b/gcc/fortran/trans-openmp.c
index 8eae7bc..8bfeeeb 100644
--- a/gcc/fortran/trans-openmp.c
+++ b/gcc/fortran/trans-openmp.c
@@ -1067,6 +1067,62 @@ gfc_omp_clause_dtor (tree clause, tree decl)
    return tem;
  }

+/* Build a conditional expression in BLOCK.  If COND_VAL is not
+   null, then the block THEN_B is executed, otherwise ELSE_VAL
+   is assigned to VAL.  */
+
+static void
+gfc_build_conditional_assign (stmtblock_t *block,
+			      tree val,
+			      tree cond_val,
+			      tree then_b,
+			      tree else_val)
+{
+  stmtblock_t cond_block;
+  tree cond, else_b;
+  tree val_ty = TREE_TYPE (val);
+
+  gfc_init_block (&cond_block);
+  gfc_add_modify (&cond_block, val, fold_convert (val_ty, else_val));
+  else_b = gfc_finish_block (&cond_block);
+  cond = fold_convert (pvoid_type_node, cond_val);
+  cond = fold_build2_loc (input_location, NE_EXPR,
+			  logical_type_node,
+			  cond, null_pointer_node);
+  gfc_add_expr_to_block (block,
+			 build3_loc (input_location,
+				     COND_EXPR,
+				     void_type_node,
+				     cond, then_b,
+				     else_b));
+}
+
+/* Build a conditional expression in BLOCK, returning a temporary
+   variable containing the result.  If COND_VAL is not null, then
+   THEN_VAL will be assigned to the variable, otherwise ELSE_VAL
+   is assigned.
+ */
+
+static tree
+gfc_build_conditional_assign_expr (stmtblock_t *block,
+				   tree cond_val,
+				   tree then_val,
+				   tree else_val)
+{
+  tree val;
+  tree val_ty = TREE_TYPE (then_val);
+  stmtblock_t cond_block;
+
+  val = create_tmp_var (val_ty);
+
+  gfc_init_block (&cond_block);
+  gfc_add_modify (&cond_block, val, then_val);
+  tree then_b = gfc_finish_block (&cond_block);
+
+  gfc_build_conditional_assign (block, val, cond_val, then_b, else_val);
+
+  return val;
+}

  void
  gfc_omp_finish_clause (tree c, gimple_seq *pre_p)
@@ -1124,17 +1180,46 @@ gfc_omp_finish_clause (tree c, gimple_seq *pre_p)
        stmtblock_t block;
        gfc_start_block (&block);
        tree type = TREE_TYPE (decl);
-      tree ptr = gfc_conv_descriptor_data_get (decl);
+      bool optional_arg_p =
+	        TREE_CODE (decl) == INDIRECT_REF
+	      && TREE_CODE (TREE_OPERAND (decl, 0)) == PARM_DECL
+	      && DECL_BY_REFERENCE (TREE_OPERAND (decl, 0))
+	      && TREE_CODE (TREE_TYPE (TREE_OPERAND (decl, 0))) == POINTER_TYPE;
+      tree ptr;
+
+      if (optional_arg_p)
+	ptr = gfc_build_conditional_assign_expr (
+		&block,
+		TREE_OPERAND (decl, 0),
+		gfc_conv_descriptor_data_get (decl),
+		null_pointer_node);
+      else
+	ptr = gfc_conv_descriptor_data_get (decl);
        ptr = fold_convert (build_pointer_type (char_type_node), ptr);
        ptr = build_fold_indirect_ref (ptr);
        OMP_CLAUSE_DECL (c) = ptr;
        c2 = build_omp_clause (input_location, OMP_CLAUSE_MAP);
        OMP_CLAUSE_SET_MAP_KIND (c2, GOMP_MAP_TO_PSET);
-      OMP_CLAUSE_DECL (c2) = decl;
+      if (optional_arg_p)
+	{
+	  ptr = create_tmp_var (TREE_TYPE (TREE_OPERAND (decl, 0)));
+	  gfc_add_modify (&block, ptr, TREE_OPERAND (decl, 0));
+
+	  OMP_CLAUSE_DECL (c2) = build_fold_indirect_ref (ptr);
+	}
+      else
+	OMP_CLAUSE_DECL (c2) = decl;
        OMP_CLAUSE_SIZE (c2) = TYPE_SIZE_UNIT (type);
        c3 = build_omp_clause (OMP_CLAUSE_LOCATION (c), OMP_CLAUSE_MAP);
        OMP_CLAUSE_SET_MAP_KIND (c3, GOMP_MAP_POINTER);
-      OMP_CLAUSE_DECL (c3) = gfc_conv_descriptor_data_get (decl);
+      if (optional_arg_p)
+	OMP_CLAUSE_DECL (c3) = gfc_build_conditional_assign_expr (
+		&block,
+		TREE_OPERAND (decl, 0),
+		gfc_conv_descriptor_data_get (decl),
+		null_pointer_node);
+      else
+	OMP_CLAUSE_DECL (c3) = gfc_conv_descriptor_data_get (decl);
        OMP_CLAUSE_SIZE (c3) = size_int (0);
        tree size = create_tmp_var (gfc_array_index_type);
        tree elemsz = TYPE_SIZE_UNIT (gfc_get_element_type (type));
@@ -1165,6 +1250,27 @@ gfc_omp_finish_clause (tree c, gimple_seq *pre_p)
  						     void_type_node, cond,
  						     then_b, else_b));
  	}
+      else if (optional_arg_p)
+	{
+	  stmtblock_t cond_block;
+	  tree then_b;
+
+	  gfc_init_block (&cond_block);
+	  gfc_add_modify (&cond_block, size,
+			  gfc_full_array_size (&cond_block, decl,
+					       GFC_TYPE_ARRAY_RANK (type)));
+	  gfc_add_modify (&cond_block, size,
+			  fold_build2 (MULT_EXPR, gfc_array_index_type,
+				       size, elemsz));
+	  then_b = gfc_finish_block (&cond_block);
+
+	  gfc_build_conditional_assign (
+		  &block,
+		  size,
+		  TREE_OPERAND (decl, 0),
+		  then_b,
+		  build_int_cst (gfc_array_index_type, 0));
+	}
        else
  	{
  	  gfc_add_modify (&block, size,
@@ -2171,7 +2277,17 @@ gfc_trans_omp_clauses (stmtblock_t *block, 
gfc_omp_clauses *clauses,
  		  if (GFC_DESCRIPTOR_TYPE_P (TREE_TYPE (decl)))
  		    {
  		      tree type = TREE_TYPE (decl);
-		      tree ptr = gfc_conv_descriptor_data_get (decl);
+		      tree ptr;
+
+		      if (n->sym->attr.optional)
+			ptr = gfc_build_conditional_assign_expr (
+				block,
+				TREE_OPERAND (decl, 0),
+				gfc_conv_descriptor_data_get (decl),
+				null_pointer_node);
+		      else
+			ptr = gfc_conv_descriptor_data_get (decl);
+
  		      ptr = fold_convert (build_pointer_type (char_type_node),
  					  ptr);
  		      ptr = build_fold_indirect_ref (ptr);
@@ -2190,34 +2306,30 @@ gfc_trans_omp_clauses (stmtblock_t *block, 
gfc_omp_clauses *clauses,

  		      /* We have to check for n->sym->attr.dimension because
  			 of scalar coarrays.  */
-		      if (n->sym->attr.pointer && n->sym->attr.dimension)
+		      if ((n->sym->attr.pointer || n->sym->attr.optional)
+			  && n->sym->attr.dimension)
  			{
  			  stmtblock_t cond_block;
  			  tree size
  			    = gfc_create_var (gfc_array_index_type, NULL);
-			  tree tem, then_b, else_b, zero, cond;
+			  tree cond = n->sym->attr.optional
+			      ? TREE_OPERAND (decl, 0)
+			      : gfc_conv_descriptor_data_get (decl);

  			  gfc_init_block (&cond_block);
-			  tem
-			    = gfc_full_array_size (&cond_block, decl,
-						   GFC_TYPE_ARRAY_RANK (type));
-			  gfc_add_modify (&cond_block, size, tem);
-			  then_b = gfc_finish_block (&cond_block);
-			  gfc_init_block (&cond_block);
-			  zero = build_int_cst (gfc_array_index_type, 0);
-			  gfc_add_modify (&cond_block, size, zero);
-			  else_b = gfc_finish_block (&cond_block);
-			  tem = gfc_conv_descriptor_data_get (decl);
-			  tem = fold_convert (pvoid_type_node, tem);
-			  cond = fold_build2_loc (input_location, NE_EXPR,
-						  logical_type_node,
-						  tem, null_pointer_node);
-			  gfc_add_expr_to_block (block,
-						 build3_loc (input_location,
-							     COND_EXPR,
-							     void_type_node,
-							     cond, then_b,
-							     else_b));
+			  gfc_add_modify (&cond_block, size,
+					  gfc_full_array_size (
+					      &cond_block, decl,
+					      GFC_TYPE_ARRAY_RANK (type)));
+			  tree then_b = gfc_finish_block (&cond_block);
+
+			  gfc_build_conditional_assign (
+				  block,
+				  size,
+				  cond,
+				  then_b,
+				  build_int_cst (gfc_array_index_type, 0));
+
  			  OMP_CLAUSE_SIZE (node) = size;
  			}
  		      else if (n->sym->attr.dimension)
-- 
2.8.1


^ permalink raw reply	[flat|nested] 65+ messages in thread

* [PATCH 5/5, OpenACC] Add tests for Fortran optional arguments in OpenACC 2.6
  2019-07-12 11:35 ` [PATCH 0/5, OpenACC] Add support for Fortran optional arguments in OpenACC Kwok Cheung Yeung
                     ` (3 preceding siblings ...)
  2019-07-12 11:39   ` [PATCH 3/5, OpenACC] Add support for allocatable arrays as optional arguments Kwok Cheung Yeung
@ 2019-07-12 11:41   ` Kwok Cheung Yeung
  4 siblings, 0 replies; 65+ messages in thread
From: Kwok Cheung Yeung @ 2019-07-12 11:41 UTC (permalink / raw)
  To: gcc-patches, fortran, jakub; +Cc: thomas

This adds testcases exercising the use of optional arguments in the 
various OpenACC directives. Where applicable, both the present and 
non-present cases are tested, with an integer, array of integers and 
allocatable array of integers as the argument.

	libgomp/
	* testsuite/libgomp.oacc-fortran/optional-cache.f95: New test.
	* testsuite/libgomp.oacc-fortran/optional-data-copyin-by-value.f90:
	New test.
	* testsuite/libgomp.oacc-fortran/optional-data-copyin.f90: New test.
	* testsuite/libgomp.oacc-fortran/optional-data-copyout.f90: New test.
	* testsuite/libgomp.oacc-fortran/optional-data-enter-exit.f90: New
	test.
	* testsuite/libgomp.oacc-fortran/optional-declare.f90: New test.
	* testsuite/libgomp.oacc-fortran/optional-firstprivate.f90: New test.
	* testsuite/libgomp.oacc-fortran/optional-host_data.f90: New test.
	* testsuite/libgomp.oacc-fortran/optional-nested-calls.f90: New test.
	* testsuite/libgomp.oacc-fortran/optional-private.f90: New test.
	* testsuite/libgomp.oacc-fortran/optional-reduction.f90: New test.
	* testsuite/libgomp.oacc-fortran/optional-update-device.f90: New test.
	* testsuite/libgomp.oacc-fortran/optional-update-host.f90: New test.
---
  .../libgomp.oacc-fortran/optional-cache.f95        |  23 ++++
  .../optional-data-copyin-by-value.f90              |  29 +++++
  .../libgomp.oacc-fortran/optional-data-copyin.f90  | 140 
+++++++++++++++++++++
  .../libgomp.oacc-fortran/optional-data-copyout.f90 |  96 ++++++++++++++
  .../optional-data-enter-exit.f90                   |  91 ++++++++++++++
  .../libgomp.oacc-fortran/optional-declare.f90      |  87 +++++++++++++
  .../libgomp.oacc-fortran/optional-firstprivate.f90 | 112 +++++++++++++++++
  .../libgomp.oacc-fortran/optional-host_data.f90    |  39 ++++++
  .../libgomp.oacc-fortran/optional-nested-calls.f90 | 135 
++++++++++++++++++++
  .../libgomp.oacc-fortran/optional-private.f90      | 115 +++++++++++++++++
  .../libgomp.oacc-fortran/optional-reduction.f90    |  69 ++++++++++
  .../optional-update-device.f90                     | 121 
++++++++++++++++++
  .../libgomp.oacc-fortran/optional-update-host.f90  | 115 +++++++++++++++++
  13 files changed, 1172 insertions(+)
  create mode 100644 
libgomp/testsuite/libgomp.oacc-fortran/optional-cache.f95
  create mode 100644 
libgomp/testsuite/libgomp.oacc-fortran/optional-data-copyin-by-value.f90
  create mode 100644 
libgomp/testsuite/libgomp.oacc-fortran/optional-data-copyin.f90
  create mode 100644 
libgomp/testsuite/libgomp.oacc-fortran/optional-data-copyout.f90
  create mode 100644 
libgomp/testsuite/libgomp.oacc-fortran/optional-data-enter-exit.f90
  create mode 100644 
libgomp/testsuite/libgomp.oacc-fortran/optional-declare.f90
  create mode 100644 
libgomp/testsuite/libgomp.oacc-fortran/optional-firstprivate.f90
  create mode 100644 
libgomp/testsuite/libgomp.oacc-fortran/optional-host_data.f90
  create mode 100644 
libgomp/testsuite/libgomp.oacc-fortran/optional-nested-calls.f90
  create mode 100644 
libgomp/testsuite/libgomp.oacc-fortran/optional-private.f90
  create mode 100644 
libgomp/testsuite/libgomp.oacc-fortran/optional-reduction.f90
  create mode 100644 
libgomp/testsuite/libgomp.oacc-fortran/optional-update-device.f90
  create mode 100644 
libgomp/testsuite/libgomp.oacc-fortran/optional-update-host.f90

diff --git a/libgomp/testsuite/libgomp.oacc-fortran/optional-cache.f95 
b/libgomp/testsuite/libgomp.oacc-fortran/optional-cache.f95
new file mode 100644
index 0000000..d828497
--- /dev/null
+++ b/libgomp/testsuite/libgomp.oacc-fortran/optional-cache.f95
@@ -0,0 +1,23 @@
+! Test that the cache directives work with optional arguments.  The effect
+! of giving a non-present argument to the cache directive is not tested as
+! it is undefined.  The test is based on gfortran.dg/goacc/cache-1.f95.
+
+! { dg-additional-options "-std=f2008" }
+
+program cache_test
+  implicit none
+  integer :: d(10), e(5,13)
+
+  call do_test(d, e)
+contains
+  subroutine do_test(d, e)
+    integer, optional :: d(10), e(5,13)
+    integer :: i
+    do concurrent (i=1:5)
+      !$acc cache (d(1:3))
+      !$acc cache (d(i:i+2))
+      !$acc cache (e(1:3,2:4))
+      !$acc cache (e(i:i+2,i+1:i+3))
+    enddo
+  end
+end
diff --git 
a/libgomp/testsuite/libgomp.oacc-fortran/optional-data-copyin-by-value.f90 
b/libgomp/testsuite/libgomp.oacc-fortran/optional-data-copyin-by-value.f90
new file mode 100644
index 0000000..5cadeed
--- /dev/null
+++ 
b/libgomp/testsuite/libgomp.oacc-fortran/optional-data-copyin-by-value.f90
@@ -0,0 +1,29 @@
+! Test OpenACC data regions with optional arguments passed by value.
+
+! { dg-do run }
+
+program test
+  implicit none
+
+  integer :: res
+
+  if (foo(27) .ne. 27) stop 1
+  if (foo(16, 18) .ne. 288) stop 1
+contains
+  function foo(x, y)
+    integer, value :: x
+    integer, value, optional :: y
+    integer :: res, foo
+
+    !$acc data copyin(x, y) copyout(res)
+    !$acc parallel
+    res = x
+    if (present(y)) then
+      res = res * y
+    end if
+    !$acc end parallel
+    !$acc end data
+
+    foo = res
+  end function foo
+end program test
diff --git 
a/libgomp/testsuite/libgomp.oacc-fortran/optional-data-copyin.f90 
b/libgomp/testsuite/libgomp.oacc-fortran/optional-data-copyin.f90
new file mode 100644
index 0000000..a30908d
--- /dev/null
+++ b/libgomp/testsuite/libgomp.oacc-fortran/optional-data-copyin.f90
@@ -0,0 +1,140 @@
+! Test OpenACC data regions with a copy-in of optional arguments.
+
+! { dg-do run }
+
+program test
+  implicit none
+
+  integer, parameter :: n = 64
+  integer :: i
+  integer :: a_int, b_int, c_int, res_int
+  integer :: a_arr(n), b_arr(n), c_arr(n), res_arr(n)
+  integer, allocatable :: a_alloc(:), b_alloc(:), c_alloc(:), res_alloc(:)
+
+  a_int = 7
+  b_int = 3
+  c_int = 11
+
+  call test_int(res_int, a_int)
+  if (res_int .ne. a_int) stop 1
+
+  call test_int(res_int, a_int, b_int)
+  if (res_int .ne. a_int * b_int) stop 2
+
+  call test_int(res_int, a_int, b_int, c_int)
+  if (res_int .ne. a_int * b_int + c_int) stop 3
+
+  do i = 1, n
+    a_arr(i) = i
+    b_arr(i) = n - i + 1
+    c_arr(i) = i * 3
+  end do
+
+  call test_array(res_arr, a_arr)
+  do i = 1, n
+    if (res_arr(i) .ne. a_arr(i)) stop 4
+  end do
+
+  call test_array(res_arr, a_arr, b_arr)
+  do i = 1, n
+    if (res_arr(i) .ne. a_arr(i) * b_arr(i)) stop 5
+  end do
+
+  call test_array(res_arr, a_arr, b_arr, c_arr)
+  do i = 1, n
+    if (res_arr(i) .ne. a_arr(i) * b_arr(i) + c_arr(i)) stop 6
+  end do
+
+  allocate (a_alloc(n))
+  allocate (b_alloc(n))
+  allocate (c_alloc(n))
+  allocate (res_alloc(n))
+
+  do i = 1, n
+    a_alloc(i) = i
+    b_alloc(i) = n - i + 1
+    c_alloc(i) = i * 3
+  end do
+
+  call test_allocatable(res_alloc, a_alloc)
+  do i = 1, n
+    if (res_alloc(i) .ne. a_alloc(i)) stop 7
+  end do
+
+  call test_allocatable(res_alloc, a_alloc, b_alloc)
+  do i = 1, n
+    if (res_alloc(i) .ne. a_alloc(i) * b_alloc(i)) stop 8
+  end do
+
+  call test_allocatable(res_alloc, a_alloc, b_alloc, c_alloc)
+  do i = 1, n
+    if (res_alloc(i) .ne. a_alloc(i) * b_alloc(i) + c_alloc(i)) stop 9
+  end do
+
+  deallocate (a_alloc)
+  deallocate (b_alloc)
+  deallocate (c_alloc)
+  deallocate (res_alloc)
+contains
+  subroutine test_int(res, a, b, c)
+    integer :: res
+    integer :: a
+    integer, optional :: b, c
+
+    !$acc data copyin(a, b, c) copyout(res)
+    !$acc parallel
+    res = a
+
+    if (present(b)) res = res * b
+
+    if (present(c)) res = res + c
+    !$acc end parallel
+    !$acc end data
+  end subroutine test_int
+
+  subroutine test_array(res, a, b, c)
+    integer :: res(n)
+    integer :: a(n)
+    integer, optional :: b(n), c(n)
+
+    !$acc data copyin(a, b, c) copyout(res)
+    !$acc parallel loop
+    do i = 1, n
+      res(i) = a(i)
+    end do
+
+    !$acc parallel loop
+    do i = 1, n
+      if (present(b)) res(i) = res(i) * b(i)
+    end do
+
+    !$acc parallel loop
+    do i = 1, n
+      if (present(c)) res(i) = res(i) + c(i)
+    end do
+    !$acc end data
+  end subroutine test_array
+
+  subroutine test_allocatable(res, a, b, c)
+    integer, allocatable :: res(:)
+    integer, allocatable  :: a(:)
+    integer, allocatable, optional :: b(:), c(:)
+
+    !$acc data copyin(a, b, c) copyout(res)
+    !$acc parallel loop
+    do i = 1, n
+      res(i) = a(i)
+    end do
+
+    !$acc parallel loop
+    do i = 1, n
+      if (present(b)) res(i) = res(i) * b(i)
+    end do
+
+    !$acc parallel loop
+    do i = 1, n
+      if (present(c)) res(i) = res(i) + c(i)
+    end do
+    !$acc end data
+  end subroutine test_allocatable
+end program test
diff --git 
a/libgomp/testsuite/libgomp.oacc-fortran/optional-data-copyout.f90 
b/libgomp/testsuite/libgomp.oacc-fortran/optional-data-copyout.f90
new file mode 100644
index 0000000..feaa31f
--- /dev/null
+++ b/libgomp/testsuite/libgomp.oacc-fortran/optional-data-copyout.f90
@@ -0,0 +1,96 @@
+! Test OpenACC data regions with a copy-out of optional arguments.
+
+! { dg-do run }
+
+program test
+  implicit none
+
+  integer, parameter :: n = 64
+  integer :: i
+  integer :: a_int, b_int, res_int
+  integer :: a_arr(n), b_arr(n), res_arr(n)
+  integer, allocatable :: a_alloc(:), b_alloc(:), res_alloc(:)
+
+  res_int = 0
+
+  call test_int(a_int, b_int)
+  if (res_int .ne. 0) stop 1
+
+  call test_int(a_int, b_int, res_int)
+  if (res_int .ne. a_int * b_int) stop 2
+
+  res_arr(:) = 0
+  do i = 1, n
+    a_arr(i) = i
+    b_arr(i) = n - i + 1
+  end do
+
+  call test_array(a_arr, b_arr)
+  do i = 1, n
+    if (res_arr(i) .ne. 0) stop 3
+  end do
+
+  call test_array(a_arr, b_arr, res_arr)
+  do i = 1, n
+    if (res_arr(i) .ne. a_arr(i) * b_arr(i)) stop 4
+  end do
+
+  allocate (a_alloc(n))
+  allocate (b_alloc(n))
+  allocate (res_alloc(n))
+
+  res_alloc(:) = 0
+  do i = 1, n
+    a_alloc(i) = i
+    b_alloc(i) = n - i + 1
+  end do
+
+  call test_allocatable(a_alloc, b_alloc)
+  do i = 1, n
+    if (res_alloc(i) .ne. 0) stop 5
+  end do
+
+  call test_allocatable(a_alloc, b_alloc, res_alloc)
+  do i = 1, n
+    if (res_alloc(i) .ne. a_alloc(i) * b_alloc(i)) stop 6
+  end do
+
+  deallocate (a_alloc)
+  deallocate (b_alloc)
+  deallocate (res_alloc)
+contains
+  subroutine test_int(a, b, res)
+    integer :: a, b
+    integer, optional :: res
+
+    !$acc data copyin(a, b) copyout(res)
+    !$acc parallel
+    if (present(res)) res = a * b
+    !$acc end parallel
+    !$acc end data
+  end subroutine test_int
+
+  subroutine test_array(a, b, res)
+    integer :: a(n), b(n)
+    integer, optional :: res(n)
+
+    !$acc data copyin(a, b) copyout(res)
+    !$acc parallel loop
+    do i = 1, n
+      if (present(res)) res(i) = a(i) * b(i)
+    end do
+    !$acc end data
+  end subroutine test_array
+
+  subroutine test_allocatable(a, b, res)
+    integer, allocatable :: a(:), b(:)
+    integer, allocatable, optional :: res(:)
+
+    !$acc data copyin(a, b) copyout(res)
+    !$acc parallel loop
+    do i = 1, n
+      if (present(res)) res(i) = a(i) * b(i)
+    end do
+    !$acc end data
+  end subroutine test_allocatable
+end program test
diff --git 
a/libgomp/testsuite/libgomp.oacc-fortran/optional-data-enter-exit.f90 
b/libgomp/testsuite/libgomp.oacc-fortran/optional-data-enter-exit.f90
new file mode 100644
index 0000000..9ed0f75
--- /dev/null
+++ b/libgomp/testsuite/libgomp.oacc-fortran/optional-data-enter-exit.f90
@@ -0,0 +1,91 @@
+! Test OpenACC unstructured enter data/exit data regions with optional
+! arguments.
+
+! { dg-do run }
+
+program test
+  implicit none
+
+  integer, parameter :: n = 64
+  integer :: a(n), b(n), c(n), res(n)
+  integer :: x, y, z, r, i
+
+  do i = 1, n
+    a(i) = i
+    b(i) = n - i + 1
+    c(i) = i * 3
+  end do
+
+  res = test_array(a)
+  do i = 1, n
+    if (res(i) .ne. a(i)) stop 1
+  end do
+
+  res = test_array(a, b)
+  do i = 1, n
+    if (res(i) .ne. a(i) * b(i)) stop 2
+  end do
+
+  res = test_array(a, b, c)
+  do i = 1, n
+    if (res(i) .ne. a(i) * b(i) + c(i)) stop 3
+  end do
+
+  x = 7
+  y = 3
+  z = 11
+
+  r = test_int(x)
+  if (r .ne. x) stop 4
+
+  r = test_int(x, y)
+  if (r .ne. x * y) stop 5
+
+  r = test_int(x, y, z)
+  if (r .ne. x * y + z) stop 6
+contains
+  function test_array(a, b, c)
+    integer :: a(n)
+    integer, optional :: b(n), c(n)
+    integer :: test_array(n), res(n)
+
+    !$acc enter data copyin(a, b, c) create(res)
+    !$acc parallel loop
+    do i = 1, n
+      res(i) = a(i)
+    end do
+
+    !$acc parallel loop
+    do i = 1, n
+      if (present(b)) then
+        res(i) = res(i) * b(i)
+      end if
+    end do
+
+    !$acc parallel loop
+    do i = 1, n
+      if (present(c)) then
+        res(i) = res(i) + c(i)
+      end if
+    end do
+    !$acc exit data copyout(res) delete(a, b, c)
+
+    test_array = res
+  end function test_array
+
+  function test_int(a, b, c)
+    integer :: a
+    integer, optional :: b, c
+    integer :: test_int, res
+
+    !$acc enter data copyin(a, b, c) create(res)
+    !$acc parallel present(a, b, c, res)
+    res = a
+    if (present(b)) res = res * b
+    if (present(c)) res = res + c
+    !$acc end parallel
+    !$acc exit data copyout(res) delete(a, b, c)
+
+    test_int = res
+  end function test_int
+end program test
diff --git a/libgomp/testsuite/libgomp.oacc-fortran/optional-declare.f90 
b/libgomp/testsuite/libgomp.oacc-fortran/optional-declare.f90
new file mode 100644
index 0000000..074e5a2
--- /dev/null
+++ b/libgomp/testsuite/libgomp.oacc-fortran/optional-declare.f90
@@ -0,0 +1,87 @@
+! Test OpenACC declare directives with optional arguments.
+
+! { dg-do run }
+
+program test
+  implicit none
+
+  integer, parameter :: n = 64
+  integer :: i
+  integer :: a_int, b_int, c_int, res_int
+  integer :: a_arr(n), b_arr(n), c_arr(n), res_arr(n)
+
+  a_int = 7
+  b_int = 3
+  c_int = 11
+
+  call test_int(res_int, a_int)
+  if (res_int .ne. a_int) stop 1
+
+  call test_int(res_int, a_int, b_int)
+  if (res_int .ne. a_int * b_int) stop 2
+
+  call test_int(res_int, a_int, b_int, c_int)
+  if (res_int .ne. a_int * b_int + c_int) stop 3
+
+  do i = 1, n
+    a_arr(i) = i
+    b_arr(i) = n - i + 1
+    c_arr(i) = i * 3
+  end do
+
+  call test_array(res_arr, a_arr)
+  do i = 1, n
+    if (res_arr(i) .ne. a_arr(i)) stop 4
+  end do
+
+  call test_array(res_arr, a_arr, b_arr)
+  do i = 1, n
+    if (res_arr(i) .ne. a_arr(i) * b_arr(i)) stop 5
+  end do
+
+  call test_array(res_arr, a_arr, b_arr, c_arr)
+  do i = 1, n
+    if (res_arr(i) .ne. a_arr(i) * b_arr(i) + c_arr(i)) stop 6
+  end do
+contains
+  subroutine test_int(res, a, b, c)
+    integer :: a
+    integer, optional :: b, c
+    !$acc declare present_or_copyin(a, b, c)
+    integer :: res
+    !$acc declare present_or_copyout(res)
+
+    !$acc parallel
+    res = a
+    if (present(b)) res = res * b
+    if (present(c)) res = res + c
+    !$acc end parallel
+  end subroutine test_int
+
+  subroutine test_array(res, a, b, c)
+    integer :: a(n)
+    integer, optional :: b(n), c(n)
+    !$acc declare present_or_copyin(a, b, c)
+    integer :: res(n)
+    !$acc declare present_or_copyout(res)
+
+    !$acc parallel loop
+    do i = 1, n
+      res(i) = a(i)
+    end do
+
+    !$acc parallel loop
+    do i = 1, n
+      if (present(b)) then
+        res(i) = res(i) * b(i)
+      end if
+    end do
+
+    !$acc parallel loop
+    do i = 1, n
+      if (present(c)) then
+        res(i) = res(i) + c(i)
+      end if
+    end do
+  end subroutine test_array
+end program test
diff --git 
a/libgomp/testsuite/libgomp.oacc-fortran/optional-firstprivate.f90 
b/libgomp/testsuite/libgomp.oacc-fortran/optional-firstprivate.f90
new file mode 100644
index 0000000..693e611
--- /dev/null
+++ b/libgomp/testsuite/libgomp.oacc-fortran/optional-firstprivate.f90
@@ -0,0 +1,112 @@
+! Test that optional arguments work in firstprivate clauses.  The effect of
+! non-present arguments in firstprivate clauses is undefined, and is not
+! tested for.
+
+! { dg-do run }
+
+program test_firstprivate
+  implicit none
+  integer, parameter :: n = 64
+
+  integer :: i, j
+  integer :: a_int, b_int, c_int, res_int
+  integer :: a_arr(n), b_arr(n), c_arr(n), res_arr(n)
+  integer, allocatable :: a_alloc(:), b_alloc(:), c_alloc(:), res_alloc(:)
+
+  a_int = 14
+  b_int = 5
+  c_int = 12
+
+  call test_int(res_int, a_int, b_int, c_int)
+  if (res_int .ne. a_int * b_int + c_int) stop 1
+
+  do i = 1, n
+    a_arr(i) = i
+    b_arr(i) = n - i + 1
+    c_arr(i) = i * 3
+  end do
+
+  call test_array(res_arr, a_arr, b_arr, c_arr)
+  do i = 1, n
+    if (res_arr(i) .ne. a_arr(i) * b_arr(i) + c_arr(i)) stop 2
+  end do
+
+  allocate(a_alloc(n))
+  allocate(b_alloc(n))
+  allocate(c_alloc(n))
+  allocate(res_alloc(n))
+
+  do i = 1, n
+    a_arr(i) = i
+    b_arr(i) = n - i + 1
+    c_arr(i) = i * 3
+  end do
+
+  call test_allocatable(res_alloc, a_alloc, b_alloc, c_alloc)
+  do i = 1, n
+    if (res_alloc(i) .ne. a_alloc(i) * b_alloc(i) + c_alloc(i)) stop 2
+  end do
+
+  deallocate(a_alloc)
+  deallocate(b_alloc)
+  deallocate(c_alloc)
+  deallocate(res_alloc)
+contains
+  subroutine test_int(res, a, b, c)
+    integer :: a
+    integer, optional :: b, c
+    integer :: res
+
+    !$acc parallel firstprivate(a, b, c) copyout(res)
+    res = a
+    if (present(b)) res = res * b
+    if (present(c)) res = res + c
+    !$acc end parallel
+  end subroutine test_int
+
+  subroutine test_array(res, a, b, c)
+    integer :: a(n)
+    integer, optional :: b(n), c(n)
+    integer :: res(n)
+
+    !$acc data copyin(a, b, c) copyout(res)
+    !$acc parallel loop firstprivate(a)
+    do i = 1, n
+      res(i) = a(i)
+    end do
+
+    !$acc parallel loop firstprivate(b)
+    do i = 1, n
+      if (present(b)) res(i) = res(i) * b(i)
+    end do
+
+    !$acc parallel loop firstprivate(c)
+    do i = 1, n
+      if (present(c)) res(i) = res(i) + c(i)
+    end do
+    !$acc end data
+  end subroutine test_array
+
+  subroutine test_allocatable(res, a, b, c)
+    integer, allocatable :: a(:)
+    integer, allocatable, optional :: b(:), c(:)
+    integer, allocatable :: res(:)
+
+    !$acc data copyin(a, b, c) copyout(res)
+    !$acc parallel loop firstprivate(a)
+    do i = 1, n
+      res(i) = a(i)
+    end do
+
+    !$acc parallel loop firstprivate(b)
+    do i = 1, n
+      if (present(b)) res(i) = res(i) * b(i)
+    end do
+
+    !$acc parallel loop firstprivate(c)
+    do i = 1, n
+      if (present(c)) res(i) = res(i) + c(i)
+    end do
+    !$acc end data
+  end subroutine test_allocatable
+end program test_firstprivate
diff --git 
a/libgomp/testsuite/libgomp.oacc-fortran/optional-host_data.f90 
b/libgomp/testsuite/libgomp.oacc-fortran/optional-host_data.f90
new file mode 100644
index 0000000..a6e41e2
--- /dev/null
+++ b/libgomp/testsuite/libgomp.oacc-fortran/optional-host_data.f90
@@ -0,0 +1,39 @@
+! Test the host_data construct with optional arguments.
+! Based on host_data-1.f90.
+
+! { dg-do run }
+! { dg-additional-options "-cpp" }
+
+program test
+  implicit none
+
+  integer, target :: i
+  integer, pointer :: ip, iph
+
+  ! Assign the same targets
+  ip => i
+  iph => i
+
+  call foo(iph)
+  call foo(iph, ip)
+contains
+  subroutine foo(iph, ip)
+    integer, pointer :: iph
+    integer, pointer, optional :: ip
+
+    !$acc data copyin(i)
+    !$acc host_data use_device(ip)
+
+    ! Test how the pointers compare inside a host_data construct
+    if (present(ip)) then
+#if ACC_MEM_SHARED
+      if (.not. associated(ip, iph)) STOP 1
+#else
+      if (associated(ip, iph)) STOP 2
+#endif
+    end if
+
+    !$acc end host_data
+    !$acc end data
+  end subroutine foo
+end program test
diff --git 
a/libgomp/testsuite/libgomp.oacc-fortran/optional-nested-calls.f90 
b/libgomp/testsuite/libgomp.oacc-fortran/optional-nested-calls.f90
new file mode 100644
index 0000000..279139f
--- /dev/null
+++ b/libgomp/testsuite/libgomp.oacc-fortran/optional-nested-calls.f90
@@ -0,0 +1,135 @@
+! Test propagation of optional arguments from within an OpenACC 
parallel region.
+
+! { dg-do run }
+
+program test
+  implicit none
+
+  integer, parameter :: n = 64
+  integer :: i
+  integer :: res_int
+  integer :: a_arr(n), b_arr(n), res_arr(n)
+  integer, allocatable :: a_alloc(:), b_alloc(:), res_alloc(:)
+
+  call test_int_caller(res_int, 5)
+  if (res_int .ne. 10) stop 1
+
+  call test_int_caller(res_int, 2, 3)
+  if (res_int .ne. 11) stop 2
+
+  do i = 1, n
+    a_arr(i) = i
+    b_arr(i) = n - i + 1
+  end do
+
+  call test_array_caller(res_arr, a_arr)
+  do i = 1, n
+    if (res_arr(i) .ne. 2 * a_arr(i)) stop 3
+  end do
+
+  call test_array_caller(res_arr, a_arr, b_arr)
+  do i = 1, n
+    if (res_arr(i) .ne. a_arr(i) * b_arr(i) + a_arr(i) + b_arr(i)) stop 4
+  end do
+
+  allocate(a_alloc(n))
+  allocate(b_alloc(n))
+  allocate(res_alloc(n))
+
+  do i = 1, n
+    a_alloc(i) = i
+    b_alloc(i) = n - i + 1
+  end do
+
+  call test_array_caller(res_arr, a_arr)
+  do i = 1, n
+    if (res_arr(i) .ne. 2 * a_alloc(i)) stop 5
+  end do
+
+  call test_array_caller(res_arr, a_arr, b_arr)
+  do i = 1, n
+    if (res_arr(i) .ne. a_arr(i) * b_alloc(i) + a_alloc(i) + 
b_alloc(i)) stop 6
+  end do
+
+  deallocate(a_alloc)
+  deallocate(b_alloc)
+  deallocate(res_alloc)
+contains
+  subroutine test_int_caller(res, a, b)
+    integer :: res, a
+    integer, optional :: b
+
+    !$acc data copyin(a, b) copyout (res)
+    !$acc parallel
+    res = a
+    if (present(b)) res = res * b
+    call test_int_callee(res, a, b)
+    !$acc end parallel
+    !$acc end data
+  end subroutine test_int_caller
+
+  subroutine test_int_callee(res, a, b)
+    !$acc routine seq
+    integer :: res, a
+    integer, optional :: b
+
+    res = res + a
+    if (present(b)) res = res + b
+  end subroutine test_int_callee
+
+  subroutine test_array_caller(res, a, b)
+    integer :: res(n), a(n), i
+    integer, optional :: b(n)
+
+    !$acc data copyin(a, b) copyout(res)
+    !$acc parallel
+    !$acc loop seq
+    do i = 1, n
+      res(i) = a(i)
+      if (present(b)) res(i) = res(i) * b(i)
+    end do
+    call test_array_callee(res, a, b)
+    !$acc end parallel
+    !$acc end data
+  end subroutine test_array_caller
+
+  subroutine test_array_callee(res, a, b)
+    !$acc routine seq
+    integer :: res(n), a(n), i
+    integer, optional :: b(n)
+
+    do i = 1, n
+      res(i) = res(i) + a(i)
+      if (present(b)) res(i) = res(i) + b(i)
+    end do
+  end subroutine test_array_callee
+
+  subroutine test_allocatable_caller(res, a, b)
+    integer :: i
+    integer, allocatable :: res(:), a(:)
+    integer, allocatable, optional :: b(:)
+
+    !$acc data copyin(a, b) copyout(res)
+    !$acc parallel
+    !$acc loop seq
+    do i = 1, n
+      res(i) = a(i)
+      if (present(b)) res(i) = res(i) * b(i)
+    end do
+    call test_array_callee(res, a, b)
+    !$acc end parallel
+    !$acc end data
+  end subroutine test_allocatable_caller
+
+  subroutine test_allocatable_callee(res, a, b)
+    !$acc routine seq
+    integer :: i
+    integer, allocatable :: res(:), a(:)
+    integer, allocatable, optional :: b(:)
+
+    do i = 1, n
+      res(i) = res(i) + a(i)
+      if (present(b)) res(i) = res(i) + b(i)
+    end do
+  end subroutine test_allocatable_callee
+end program test
diff --git a/libgomp/testsuite/libgomp.oacc-fortran/optional-private.f90 
b/libgomp/testsuite/libgomp.oacc-fortran/optional-private.f90
new file mode 100644
index 0000000..0320bbb
--- /dev/null
+++ b/libgomp/testsuite/libgomp.oacc-fortran/optional-private.f90
@@ -0,0 +1,115 @@
+! Test that optional arguments work in private clauses.  The effect of
+! non-present arguments in private clauses is undefined, and is not tested
+! for.  The tests are based on those in private-variables.f90.
+
+! { dg-do run }
+
+program main
+  implicit none
+
+  type vec3
+     integer x, y, z, attr(13)
+  end type vec3
+  integer :: x
+  type(vec3) :: pt
+  integer :: arr(2)
+
+  call t1(x)
+  call t2(pt)
+  call t3(arr)
+contains
+
+  ! Test of gang-private variables declared on loop directive.
+
+  subroutine t1(x)
+    integer, optional :: x
+    integer :: i, arr(32)
+
+    do i = 1, 32
+       arr(i) = i
+    end do
+
+    !$acc parallel copy(arr) num_gangs(32) num_workers(8) vector_length(32)
+    !$acc loop gang private(x)
+    do i = 1, 32
+       x = i * 2;
+       arr(i) = arr(i) + x
+    end do
+    !$acc end parallel
+
+    do i = 1, 32
+       if (arr(i) .ne. i * 3) STOP 1
+    end do
+  end subroutine t1
+
+
+  ! Test of gang-private addressable variable declared on loop 
directive, with
+  ! broadcasting to partitioned workers.
+
+  subroutine t2(pt)
+    integer i, j, arr(0:32*32)
+    type(vec3), optional :: pt
+
+    do i = 0, 32*32-1
+       arr(i) = i
+    end do
+
+    !$acc parallel copy(arr) num_gangs(32) num_workers(8) vector_length(32)
+    !$acc loop gang private(pt)
+    do i = 0, 31
+       pt%x = i
+       pt%y = i * 2
+       pt%z = i * 4
+       pt%attr(5) = i * 6
+
+       !$acc loop vector
+       do j = 0, 31
+          arr(i * 32 + j) = arr(i * 32 + j) + pt%x + pt%y + pt%z + 
pt%attr(5);
+       end do
+    end do
+    !$acc end parallel
+
+    do i = 0, 32 * 32 - 1
+       if (arr(i) .ne. i + (i / 32) * 13) STOP 2
+    end do
+  end subroutine t2
+
+  ! Test of vector-private variables declared on loop directive. Array 
type.
+
+  subroutine t3(pt)
+    integer, optional :: pt(2)
+    integer :: i, j, k, idx, arr(0:32*32*32)
+
+    do i = 0, 32*32*32-1
+       arr(i) = i
+    end do
+
+    !$acc parallel copy(arr) num_gangs(32) num_workers(8) vector_length(32)
+    !$acc loop gang
+    do i = 0, 31
+       !$acc loop worker
+       do j = 0, 31
+          !$acc loop vector private(pt)
+          do k = 0, 31
+             pt(1) = ieor(i, j * 3)
+             pt(2) = ior(i, j * 5)
+             arr(i * 1024 + j * 32 + k) = arr(i * 1024 + j * 32 + k) + 
pt(1) * k
+             arr(i * 1024 + j * 32 + k) = arr(i * 1024 + j * 32 + k) + 
pt(2) * k
+          end do
+       end do
+    end do
+    !$acc end parallel
+
+    do i = 0, 32 - 1
+       do j = 0, 32 -1
+          do k = 0, 32 - 1
+             idx = i * 1024 + j * 32 + k
+             if (arr(idx) .ne. idx + ieor(i, j * 3) * k + ior(i, j * 5) 
* k) then
+                STOP 3
+             end if
+          end do
+       end do
+    end do
+  end subroutine t3
+
+end program main
diff --git 
a/libgomp/testsuite/libgomp.oacc-fortran/optional-reduction.f90 
b/libgomp/testsuite/libgomp.oacc-fortran/optional-reduction.f90
new file mode 100644
index 0000000..b76db3e
--- /dev/null
+++ b/libgomp/testsuite/libgomp.oacc-fortran/optional-reduction.f90
@@ -0,0 +1,69 @@
+! Test optional arguments in reduction clauses.  The effect of
+! non-present arguments in reduction clauses is undefined, and is not 
tested
+! for.  The tests are based on those in reduction-1.f90.
+
+! { dg-do run }
+! { dg-additional-options "-w" }
+
+program optional_reduction
+  implicit none
+
+  integer :: rg, rw, rv, rc
+
+  rg = 0
+  rw = 0
+  rv = 0
+  rc = 0
+
+  call do_test(rg, rw, rv, rc)
+contains
+  subroutine do_test(rg, rw, rv, rc)
+    integer, parameter     :: n = 10, ng = 8, nw = 4, vl = 32
+    integer, optional      :: rg, rw, rv, rc
+    integer                :: i, vresult
+    integer, dimension (n) :: array
+
+    vresult = 0
+    do i = 1, n
+       array(i) = i
+    end do
+
+    !$acc parallel num_gangs(ng) copy(rg)
+    !$acc loop reduction(+:rg) gang
+    do i = 1, n
+       rg = rg + array(i)
+    end do
+    !$acc end parallel
+
+    !$acc parallel num_workers(nw) copy(rw)
+    !$acc loop reduction(+:rw) worker
+    do i = 1, n
+       rw = rw + array(i)
+    end do
+    !$acc end parallel
+
+    !$acc parallel vector_length(vl) copy(rv)
+    !$acc loop reduction(+:rv) vector
+    do i = 1, n
+       rv = rv + array(i)
+    end do
+    !$acc end parallel
+
+    !$acc parallel num_gangs(ng) num_workers(nw) vector_length(vl) copy(rc)
+    !$acc loop reduction(+:rc) gang worker vector
+    do i = 1, n
+       rc = rc + array(i)
+    end do
+    !$acc end parallel
+
+    ! Verify the results
+    do i = 1, n
+       vresult = vresult + array(i)
+    end do
+
+    if (rg .ne. vresult) STOP 1
+    if (rw .ne. vresult) STOP 2
+    if (rv .ne. vresult) STOP 3
+    if (rc .ne. vresult) STOP 4
+  end subroutine do_test
+end program optional_reduction
diff --git 
a/libgomp/testsuite/libgomp.oacc-fortran/optional-update-device.f90 
b/libgomp/testsuite/libgomp.oacc-fortran/optional-update-device.f90
new file mode 100644
index 0000000..57f6900
--- /dev/null
+++ b/libgomp/testsuite/libgomp.oacc-fortran/optional-update-device.f90
@@ -0,0 +1,121 @@
+! Test OpenACC update to device with an optional argument.
+
+! { dg-do run }
+
+program optional_update_device
+  implicit none
+
+  integer, parameter :: n = 64
+  integer :: i
+  integer :: a_int, b_int, res_int
+  integer :: a_arr(n), b_arr(n), res_arr(n)
+  integer, allocatable :: a_alloc(:), b_alloc(:), res_alloc(:)
+
+  a_int = 5
+  b_int = 11
+
+  call test_int(res_int, a_int)
+  if (res_int .ne. a_int) stop 1
+
+  call test_int(res_int, a_int, b_int)
+  if (res_int .ne. a_int * b_int) stop 2
+
+  res_arr(:) = 0
+  do i = 1, n
+    a_arr(i) = i
+    b_arr(i) = n - i + 1
+  end do
+
+  call test_array(res_arr, a_arr)
+  do i = 1, n
+    if (res_arr(i) .ne. a_arr(i)) stop 3
+  end do
+
+  call test_array(res_arr, a_arr, b_arr)
+  do i = 1, n
+    if (res_arr(i) .ne. a_arr(i) * b_arr(i)) stop 4
+  end do
+
+  allocate (a_alloc(n))
+  allocate (b_alloc(n))
+  allocate (res_alloc(n))
+
+  res_alloc(:) = 0
+  do i = 1, n
+    a_alloc(i) = i
+    b_alloc(i) = n - i + 1
+  end do
+
+  call test_allocatable(res_alloc, a_alloc)
+  do i = 1, n
+    if (res_alloc(i) .ne. a_alloc(i)) stop 5
+  end do
+
+  call test_allocatable(res_alloc, a_alloc, b_alloc)
+  do i = 1, n
+    if (res_alloc(i) .ne. a_alloc(i) * b_alloc(i)) stop 6
+  end do
+
+  deallocate (a_alloc)
+  deallocate (b_alloc)
+  deallocate (res_alloc)
+contains
+  subroutine test_int(res, a, b)
+    integer :: res
+    integer :: a
+    integer, optional :: b
+
+    !$acc data create(a, b, res)
+    !$acc update device(a, b)
+    !$acc parallel
+    res = a
+    if (present(b)) res = res * b
+    !$acc end parallel
+    !$acc update self(res)
+    !$acc end data
+  end subroutine test_int
+
+  subroutine test_array(res, a, b)
+    integer :: res(n)
+    integer :: a(n)
+    integer, optional :: b(n)
+
+    !$acc data create(a, b, res)
+    !$acc update device(a, b)
+    !$acc parallel loop
+    do i = 1, n
+      res(i) = a(i)
+    end do
+
+    !$acc parallel loop
+    do i = 1, n
+      if (present(b)) then
+        res(i) = res(i) * b(i)
+      end if
+    end do
+    !$acc update self(res)
+    !$acc end data
+  end subroutine test_array
+
+  subroutine test_allocatable(res, a, b)
+    integer, allocatable :: res(:)
+    integer, allocatable :: a(:)
+    integer, allocatable, optional :: b(:)
+
+    !$acc data create(a, b, res)
+    !$acc update device(a, b)
+    !$acc parallel loop
+    do i = 1, n
+      res(i) = a(i)
+    end do
+
+    !$acc parallel loop
+    do i = 1, n
+      if (present(b)) then
+        res(i) = res(i) * b(i)
+      end if
+    end do
+    !$acc update self(res)
+    !$acc end data
+  end subroutine test_allocatable
+end program optional_update_device
diff --git 
a/libgomp/testsuite/libgomp.oacc-fortran/optional-update-host.f90 
b/libgomp/testsuite/libgomp.oacc-fortran/optional-update-host.f90
new file mode 100644
index 0000000..0f3a903
--- /dev/null
+++ b/libgomp/testsuite/libgomp.oacc-fortran/optional-update-host.f90
@@ -0,0 +1,115 @@
+! Test OpenACC update to host with an optional argument.
+
+! { dg-do run }
+
+program optional_update_host
+  implicit none
+
+  integer, parameter :: n = 64
+  integer :: i
+  integer :: a_int, b_int, res_int
+  integer :: a_arr(n), b_arr(n), res_arr(n)
+  integer, allocatable :: a_alloc(:), b_alloc(:), res_alloc(:)
+
+  a_int = 5
+  b_int = 11
+  res_int = 0
+
+  call test_int(a_int, b_int)
+  if (res_int .ne. 0) stop 1
+
+  call test_int(a_int, b_int, res_int)
+  if (res_int .ne. a_int * b_int) stop 2
+
+  res_arr(:) = 0
+  do i = 1, n
+    a_arr(i) = i
+    b_arr(i) = n - i + 1
+  end do
+
+  call test_array(a_arr, b_arr)
+  do i = 1, n
+    if (res_arr(i) .ne. 0) stop 1
+  end do
+
+  call test_array(a_arr, b_arr, res_arr)
+  do i = 1, n
+    if (res_arr(i) .ne. a_arr(i) * b_arr(i)) stop 2
+  end do
+
+  allocate(a_alloc(n))
+  allocate(b_alloc(n))
+  allocate(res_alloc(n))
+
+  res_alloc(:) = 0
+  do i = 1, n
+    a_alloc(i) = i
+    b_alloc(i) = n - i + 1
+  end do
+
+  call test_allocatable(a_alloc, b_alloc)
+  do i = 1, n
+    if (res_alloc(i) .ne. 0) stop 1
+  end do
+
+  call test_allocatable(a_alloc, b_alloc, res_alloc)
+  do i = 1, n
+    if (res_alloc(i) .ne. a_alloc(i) * b_alloc(i)) stop 2
+  end do
+
+  deallocate(a_alloc)
+  deallocate(b_alloc)
+  deallocate(res_alloc)
+contains
+  subroutine test_int(a, b, res)
+    integer :: a, b
+    integer, optional :: res
+
+    !$acc data create(a, b, res)
+    !$acc update device(a, b)
+    !$acc parallel
+    if (present(res)) res = a
+    if (present(res)) res = res * b
+    !$acc end parallel
+    !$acc update self(res)
+    !$acc end data
+  end subroutine test_int
+
+  subroutine test_array(a, b, res)
+    integer :: a(n), b(n)
+    integer, optional :: res(n)
+
+    !$acc data create(a, b, res)
+    !$acc update device(a, b)
+    !$acc parallel loop
+    do i = 1, n
+      if (present(res)) res(i) = a(i)
+    end do
+
+    !$acc parallel loop
+    do i = 1, n
+      if (present(res)) res(i) = res(i) * b(i)
+    end do
+    !$acc update self(res)
+    !$acc end data
+  end subroutine test_array
+
+  subroutine test_allocatable(a, b, res)
+    integer, allocatable :: a(:), b(:)
+    integer, allocatable, optional :: res(:)
+
+    !$acc data create(a, b, res)
+    !$acc update device(a, b)
+    !$acc parallel loop
+    do i = 1, n
+      if (present(res)) res(i) = a(i)
+    end do
+
+    !$acc parallel loop
+    do i = 1, n
+      if (present(res)) res(i) = res(i) * b(i)
+    end do
+    !$acc update self(res)
+    !$acc end data
+  end subroutine test_allocatable
+end program optional_update_host
-- 
2.8.1


^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: [PATCH 2/5, OpenACC] Support Fortran optional arguments in the firstprivate clause
  2019-07-12 11:37   ` [PATCH 2/5, OpenACC] Support Fortran optional arguments in the firstprivate clause Kwok Cheung Yeung
@ 2019-07-12 11:42     ` Jakub Jelinek
  2019-07-17 18:08       ` Kwok Cheung Yeung
  2019-07-29 21:01       ` Kwok Cheung Yeung
  0 siblings, 2 replies; 65+ messages in thread
From: Jakub Jelinek @ 2019-07-12 11:42 UTC (permalink / raw)
  To: Kwok Cheung Yeung; +Cc: gcc-patches, fortran, thomas

On Fri, Jul 12, 2019 at 12:36:13PM +0100, Kwok Cheung Yeung wrote:
> --- a/gcc/omp-general.c
> +++ b/gcc/omp-general.c
> @@ -48,6 +48,20 @@ omp_find_clause (tree clauses, enum omp_clause_code kind)
>    return NULL_TREE;
>  }
> 
> +/* Return true if DECL is a Fortran optional argument.  */
> +
> +bool
> +omp_is_optional_argument (tree decl)
> +{
> +  /* A passed-by-reference Fortran optional argument is similar to
> +     a normal argument, but since it can be null the type is a
> +     POINTER_TYPE rather than a REFERENCE_TYPE.  */
> +  return lang_GNU_Fortran ()
> +        && TREE_CODE (decl) == PARM_DECL
> +        && DECL_BY_REFERENCE (decl)
> +	 && TREE_CODE (TREE_TYPE (decl)) == POINTER_TYPE;
> +}

This should be done through a langhook.
Are really all PARM_DECLs wtih DECL_BY_REFERENCE and pointer type optional
arguments?  I mean, POINTER_TYPE is used for a lot of cases.

	Jakub

^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: [PATCH 2/5, OpenACC] Support Fortran optional arguments in the firstprivate clause
  2019-07-12 11:42     ` Jakub Jelinek
@ 2019-07-17 18:08       ` Kwok Cheung Yeung
  2019-07-17 20:49         ` Tobias Burnus
  2019-07-29 21:01       ` Kwok Cheung Yeung
  1 sibling, 1 reply; 65+ messages in thread
From: Kwok Cheung Yeung @ 2019-07-17 18:08 UTC (permalink / raw)
  To: Jakub Jelinek; +Cc: gcc-patches, fortran, thomas

On 12/07/2019 12:41 pm, Jakub Jelinek wrote:
> This should be done through a langhook.
> Are really all PARM_DECLs wtih DECL_BY_REFERENCE and pointer type optional
> arguments?  I mean, POINTER_TYPE is used for a lot of cases.

Hmmm... I thought it was the case that if you pass an argument in by reference 
(the default) in Fortran, the PARM_DECL will always be a reference to the 
argument type if non-optional, or a pointer if optional. However, fixed-shape 
arrays are passed in via a pointer whether optional or not...

I also experimented with passing in a pointer by value, but it seems like that 
is not allowed. e.g.

   subroutine foo(x)
     integer, pointer, value :: x
   end subroutine foo

results in:

    11 |     integer, pointer, value :: x
       |                           1
Error: VALUE attribute conflicts with POINTER attribute at (1)

Are there any more examples in Fortran where a PARM_DECL is a pointer type 
without being optional?

In the Fortran FE, optional arguments are indicated by setting attr.optional on 
the gfc_symbol for the parameter, but the OMP lowering works on a tree - is it 
somehow possible to get from the tree back to the gfc_symbol? If so, that would 
be a more reliable method of detecting optional arguments.

Thanks

Kwok

^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: [PATCH 2/5, OpenACC] Support Fortran optional arguments in the firstprivate clause
  2019-07-17 18:08       ` Kwok Cheung Yeung
@ 2019-07-17 20:49         ` Tobias Burnus
  2019-07-18  9:30           ` Tobias Burnus
  0 siblings, 1 reply; 65+ messages in thread
From: Tobias Burnus @ 2019-07-17 20:49 UTC (permalink / raw)
  To: Kwok Cheung Yeung, Jakub Jelinek; +Cc: gcc-patches, fortran, thomas

Am 17.07.19 um 19:53 schrieb Kwok Cheung Yeung:
> On 12/07/2019 12:41 pm, Jakub Jelinek wrote:
>> This should be done through a langhook.
>> Are really all PARM_DECLs wtih DECL_BY_REFERENCE and pointer type
>> optional
>> arguments?  I mean, POINTER_TYPE is used for a lot of cases.
>
> Hmmm... I thought it was the case that if you pass an argument in by
> reference (the default) in Fortran, the PARM_DECL will always be a
> reference to the argument type if non-optional, or a pointer if
> optional. However, fixed-shape arrays are passed in via a pointer
> whether optional or not...

[I have to admit that I have not yet read the OpenACC (nor OpenMP 5)
spec to know the semantics and whether it matters if something is a true
pointer or just optional.]


The following is a rather special case (matching a C "void *" pointer),
which is useless without later casting the argument ("c_f_pointer"
call), but it is a pointer argument which is not by reference and not
optional.


use iso_c_binding
implicit none
call foo(c_null_ptr)
contains
  subroutine foo(x)
    type(c_ptr), value :: x ! Matches a C 'void *' pointer
  end subroutine foo
end

Maybe there are more methods, but that requires some pondering.


> In the Fortran FE, optional arguments are indicated by setting
> attr.optional on the gfc_symbol for the parameter, but the OMP
> lowering works on a tree - is it somehow possible to get from the tree
> back to the gfc_symbol? If so, that would be a more reliable method of
> detecting optional arguments. 

The gfc_symbol etc. is gone. The only possibility is to store some extra
data in the language-dependent part of the tree, i.e. using
DECL_LANG_SPECIFIC. Cf. lang_decl in trans.h and the various #defines
which use DECL_LANG_SPECIFIC.

Cheers,

Tobias

^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: [PATCH 2/5, OpenACC] Support Fortran optional arguments in the firstprivate clause
  2019-07-17 20:49         ` Tobias Burnus
@ 2019-07-18  9:30           ` Tobias Burnus
  2019-07-18 11:45             ` Kwok Cheung Yeung
  0 siblings, 1 reply; 65+ messages in thread
From: Tobias Burnus @ 2019-07-18  9:30 UTC (permalink / raw)
  To: Kwok Cheung Yeung, Jakub Jelinek; +Cc: gcc-patches, fortran, thomas

Hi all,

I played around and came up with another second way one gets a single "*" without
'optional'.

I haven't checked whether which of those match the proposed omp_is_optional_argument's
+        && DECL_BY_REFERENCE (decl)
+	 && TREE_CODE (TREE_TYPE (decl)) == POINTER_TYPE;
nor whether some checks reject any of those with OpenACC (or OpenMP).

In any case, the dump of "type(c_ptr),value", "integer, dimension(1)" and "integer,optional"
is:

static void foo (void *, integer(kind=4)[1] *, integer(kind=4) *);


Actually, if one combines VALUE with OPTIONAL, it gets even more interesting.
To implement it, one has two choices:
* pass a copy by reference (or NULL)
* pass by value (including a dummy value if absent) and denote the state as
  extra argument.

The latter is done in gfortran, cf. PR fortran/35203, following the IBM compiler.


I am not sure whether it does need special care fore OpenACC (or OpenMP 5) offloading,
but that's at least a case which is not handled by the patch.


Actually, there is a bug: the declaration of the function and the definition of
the function is not the same - one misses the hidden argument :-(

That's now PR fortran/91196.


Fortran code - which now also contains VALUE, OPTIONAL:

use iso_c_binding
implicit none
logical(kind=c_bool) :: is_present
integer :: y(1)
y(1) = 5
is_present = foo(c_null_ptr, y)
contains
  logical(kind=c_bool) function foo(x, y, z, z2)
    type(c_ptr), value :: x ! Matches a C 'void *' pointer
    integer, target :: y(1)
    integer, optional :: z
    integer, value, optional :: z2

    foo = present(z2)
  end function foo
end


Tobias

^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: [PATCH 2/5, OpenACC] Support Fortran optional arguments in the firstprivate clause
  2019-07-18  9:30           ` Tobias Burnus
@ 2019-07-18 11:45             ` Kwok Cheung Yeung
  0 siblings, 0 replies; 65+ messages in thread
From: Kwok Cheung Yeung @ 2019-07-18 11:45 UTC (permalink / raw)
  To: Tobias Burnus, Jakub Jelinek; +Cc: gcc-patches, fortran, thomas

On 18/07/2019 10:28 am, Tobias Burnus wrote:
> Hi all,
> 
> I played around and came up with another second way one gets a single "*" without
> 'optional'.
> 
> I haven't checked whether which of those match the proposed omp_is_optional_argument's
> +        && DECL_BY_REFERENCE (decl)
> +	 && TREE_CODE (TREE_TYPE (decl)) == POINTER_TYPE;
> nor whether some checks reject any of those with OpenACC (or OpenMP).
> 
> In any case, the dump of "type(c_ptr),value", "integer, dimension(1)" and "integer,optional"
> is:
> 
> static void foo (void *, integer(kind=4)[1] *, integer(kind=4) *);
> 

The case of the fixed-length array currently doesn't work properly with 
omp_is_optional_argument, as it returns true whether or not it is optional. 
Indeed, the PARM_DECL doesn't seem to change between optional and non-optional, 
so it is probably impossible to discern via the tree unless some extra 
information is added by the front-end.

However, optional arrays still 'just work' with my patches (most of the 
testcases include tests for arrays in optional arguments). I believe this is 
because the existing code must already deal with pointers to arrays, so the 
false positive simply does not matter on the codepath taken. The new case of a 
null pointer (in the case of a non-present optional argument) was dealt with by 
making operations on null pointers into NOPs.

> 
> Actually, if one combines VALUE with OPTIONAL, it gets even more interesting.
> To implement it, one has two choices:
> * pass a copy by reference (or NULL)
> * pass by value (including a dummy value if absent) and denote the state as
>    extra argument.
> 
> The latter is done in gfortran, cf. PR fortran/35203, following the IBM compiler.
> 
> 
> I am not sure whether it does need special care fore OpenACC (or OpenMP 5) offloading,
> but that's at least a case which is not handled by the patch.
> 

Optional by-value arguments are tested in optional-data-copyin-by-value.f90. 
They do not need extra handling, since from the OACC lowering perspective they 
are just two bog-standard integral values of no special interest.

Kwok

^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: [PATCH 2/5, OpenACC] Support Fortran optional arguments in the firstprivate clause
  2019-07-12 11:42     ` Jakub Jelinek
  2019-07-17 18:08       ` Kwok Cheung Yeung
@ 2019-07-29 21:01       ` Kwok Cheung Yeung
  2019-07-31 12:54         ` Jakub Jelinek
  2019-10-07  9:26         ` Thomas Schwinge
  1 sibling, 2 replies; 65+ messages in thread
From: Kwok Cheung Yeung @ 2019-07-29 21:01 UTC (permalink / raw)
  To: Jakub Jelinek; +Cc: gcc-patches, fortran, thomas, Tobias Burnus

On 12/07/2019 12:41 pm, Jakub Jelinek wrote:
>> +/* Return true if DECL is a Fortran optional argument.  */
>> +
>> +bool
>> +omp_is_optional_argument (tree decl)
>> +{
>> +  /* A passed-by-reference Fortran optional argument is similar to
>> +     a normal argument, but since it can be null the type is a
>> +     POINTER_TYPE rather than a REFERENCE_TYPE.  */
>> +  return lang_GNU_Fortran ()
>> +        && TREE_CODE (decl) == PARM_DECL
>> +        && DECL_BY_REFERENCE (decl)
>> +	 && TREE_CODE (TREE_TYPE (decl)) == POINTER_TYPE;
>> +}
> 
> This should be done through a langhook.
> Are really all PARM_DECLs wtih DECL_BY_REFERENCE and pointer type optional
> arguments?  I mean, POINTER_TYPE is used for a lot of cases.
> 

I have now added a language hook for omp_is_optional_argument, implemented only 
for Fortran. In the Fortran FE, I have introduced a language-specific decl flag 
that is set to true during the construction of the PARM_DECLs for a function if 
the symbol for the parameter has attr.optional set. The implementation of 
omp_is_optional_argument checks this flag - this way, there should be no false 
positives.

This implementation of omp_is_optional_argument returns true for both 
by-reference and by-value optional arguments, so an extra check of the type is 
needed to differentiate between the two. I have also made by-reference optional 
arguments return true for gfc_omp_privatize_by_reference (since they should 
behave like regular arguments if present), which simplifies the code a little.

 >  		if (omp_is_reference (new_var)
 > 		    && TREE_CODE (TREE_TYPE (new_var)) != POINTER_TYPE)

As is, this code in lower_omp_target will always reject optional arguments, so 
it must be changed. This was introduced in commit r261025 (SVN trunk) as a fix 
for PR 85879, but it also breaks support for arrays in firstprivate, which was 
probably an unintended side-effect. I have found that allowing POINTER_TYPEs 
that are also DECL_BY_REFERENCE through in this condition allows both optional 
arguments and arrays to work without regressing the tests in r261025.

Okay for trunk?

Kwok

	gcc/fortran/
	* f95-lang.c (LANG_HOOKS_OMP_IS_OPTIONAL_ARGUMENT): Define to
	gfc_omp_is_optional_argument.
	* trans-decl.c (create_function_arglist): Set
	GFC_DECL_OPTIONAL_ARGUMENT in the generated decl if the parameter is
	optional.
	* trans-openmp.c (gfc_omp_is_optional_argument): New.
	(gfc_omp_privatize_by_reference): Return true if the decl is an
	optional pass-by-reference argument.
	* trans.h (gfc_omp_is_optional_argument): New declaration.
	(lang_decl): Add new optional_arg field.
	(GFC_DECL_OPTIONAL_ARGUMENT): New macro.

	gcc/
	* langhooks-def.h (LANG_HOOKS_OMP_IS_OPTIONAL_ARGUMENT): Default to
	false.
	(LANG_HOOKS_DECLS): Add LANG_HOOKS_OMP_IS_OPTIONAL_ARGUMENT.
	* langhooks.h (omp_is_optional_argument): New hook.
	* omp-general.c (omp_is_optional_argument): New.
	* omp-general.h (omp_is_optional_argument): New declaration.
	* omp-low.c (lower_omp_target): Create temporary for received value
	and take the address for new_var if the original variable was a
	DECL_BY_REFERENCE.  Use size of referenced object when a
	pass-by-reference optional argument used as argument to firstprivate.
---
  gcc/fortran/f95-lang.c     |  2 ++
  gcc/fortran/trans-decl.c   |  5 +++++
  gcc/fortran/trans-openmp.c | 13 +++++++++++++
  gcc/fortran/trans.h        |  4 ++++
  gcc/langhooks-def.h        |  2 ++
  gcc/langhooks.h            |  3 +++
  gcc/omp-general.c          |  8 ++++++++
  gcc/omp-general.h          |  1 +
  gcc/omp-low.c              |  7 +++++--
  9 files changed, 43 insertions(+), 2 deletions(-)

diff --git a/gcc/fortran/f95-lang.c b/gcc/fortran/f95-lang.c
index 6b9f490..2467cd9 100644
--- a/gcc/fortran/f95-lang.c
+++ b/gcc/fortran/f95-lang.c
@@ -113,6 +113,7 @@ static const struct attribute_spec gfc_attribute_table[] =
  #undef LANG_HOOKS_TYPE_FOR_MODE
  #undef LANG_HOOKS_TYPE_FOR_SIZE
  #undef LANG_HOOKS_INIT_TS
+#undef LANG_HOOKS_OMP_IS_OPTIONAL_ARGUMENT
  #undef LANG_HOOKS_OMP_PRIVATIZE_BY_REFERENCE
  #undef LANG_HOOKS_OMP_PREDETERMINED_SHARING
  #undef LANG_HOOKS_OMP_REPORT_DECL
@@ -145,6 +146,7 @@ static const struct attribute_spec gfc_attribute_table[] =
  #define LANG_HOOKS_TYPE_FOR_MODE	gfc_type_for_mode
  #define LANG_HOOKS_TYPE_FOR_SIZE	gfc_type_for_size
  #define LANG_HOOKS_INIT_TS		gfc_init_ts
+#define LANG_HOOKS_OMP_IS_OPTIONAL_ARGUMENT	gfc_omp_is_optional_argument
  #define LANG_HOOKS_OMP_PRIVATIZE_BY_REFERENCE	gfc_omp_privatize_by_reference
  #define LANG_HOOKS_OMP_PREDETERMINED_SHARING	gfc_omp_predetermined_sharing
  #define LANG_HOOKS_OMP_REPORT_DECL		gfc_omp_report_decl
diff --git a/gcc/fortran/trans-decl.c b/gcc/fortran/trans-decl.c
index 64ce4bb..14f4d21 100644
--- a/gcc/fortran/trans-decl.c
+++ b/gcc/fortran/trans-decl.c
@@ -2632,6 +2632,11 @@ create_function_arglist (gfc_symbol * sym)
  	  && (!f->sym->attr.proc_pointer
  	      && f->sym->attr.flavor != FL_PROCEDURE))
  	DECL_BY_REFERENCE (parm) = 1;
+      if (f->sym->attr.optional)
+	{
+	  gfc_allocate_lang_decl (parm);
+	  GFC_DECL_OPTIONAL_ARGUMENT (parm) = 1;
+	}

        gfc_finish_decl (parm);
        gfc_finish_decl_attrs (parm, &f->sym->attr);
diff --git a/gcc/fortran/trans-openmp.c b/gcc/fortran/trans-openmp.c
index 8eae7bc..a117bcc 100644
--- a/gcc/fortran/trans-openmp.c
+++ b/gcc/fortran/trans-openmp.c
@@ -47,6 +47,15 @@ along with GCC; see the file COPYING3.  If not see

  int ompws_flags;

+/* True if OpenMP should treat this DECL as an optional argument.  */
+
+bool
+gfc_omp_is_optional_argument (const_tree decl)
+{
+  return DECL_LANG_SPECIFIC (decl)
+	 && GFC_DECL_OPTIONAL_ARGUMENT (decl);
+}
+
  /* True if OpenMP should privatize what this DECL points to rather
     than the DECL itself.  */

@@ -59,6 +68,10 @@ gfc_omp_privatize_by_reference (const_tree decl)
        && (!DECL_ARTIFICIAL (decl) || TREE_CODE (decl) == PARM_DECL))
      return true;

+  if (TREE_CODE (type) == POINTER_TYPE
+      && gfc_omp_is_optional_argument (decl))
+    return true;
+
    if (TREE_CODE (type) == POINTER_TYPE)
      {
        /* Array POINTER/ALLOCATABLE have aggregate types, all user variables
diff --git a/gcc/fortran/trans.h b/gcc/fortran/trans.h
index 0305d33..7f9f6e8 100644
--- a/gcc/fortran/trans.h
+++ b/gcc/fortran/trans.h
@@ -776,6 +776,7 @@ struct array_descr_info;
  bool gfc_get_array_descr_info (const_tree, struct array_descr_info *);

  /* In trans-openmp.c */
+bool gfc_omp_is_optional_argument (const_tree);
  bool gfc_omp_privatize_by_reference (const_tree);
  enum omp_clause_default_kind gfc_omp_predetermined_sharing (tree);
  tree gfc_omp_report_decl (tree);
@@ -989,6 +990,7 @@ struct GTY(()) lang_decl {
    tree token, caf_offset;
    unsigned int scalar_allocatable : 1;
    unsigned int scalar_pointer : 1;
+  unsigned int optional_arg : 1;
  };


@@ -1003,6 +1005,8 @@ struct GTY(()) lang_decl {
    (DECL_LANG_SPECIFIC (node)->scalar_allocatable)
  #define GFC_DECL_SCALAR_POINTER(node) \
    (DECL_LANG_SPECIFIC (node)->scalar_pointer)
+#define GFC_DECL_OPTIONAL_ARGUMENT(node) \
+  (DECL_LANG_SPECIFIC (node)->optional_arg)
  #define GFC_DECL_GET_SCALAR_ALLOCATABLE(node) \
    (DECL_LANG_SPECIFIC (node) ? GFC_DECL_SCALAR_ALLOCATABLE (node) : 0)
  #define GFC_DECL_GET_SCALAR_POINTER(node) \
diff --git a/gcc/langhooks-def.h b/gcc/langhooks-def.h
index a059841..55d5fe0 100644
--- a/gcc/langhooks-def.h
+++ b/gcc/langhooks-def.h
@@ -236,6 +236,7 @@ extern tree lhd_unit_size_without_reusable_padding (tree);
  #define LANG_HOOKS_WARN_UNUSED_GLOBAL_DECL lhd_warn_unused_global_decl
  #define LANG_HOOKS_POST_COMPILATION_PARSING_CLEANUPS NULL
  #define LANG_HOOKS_DECL_OK_FOR_SIBCALL	lhd_decl_ok_for_sibcall
+#define LANG_HOOKS_OMP_IS_OPTIONAL_ARGUMENT hook_bool_const_tree_false
  #define LANG_HOOKS_OMP_PRIVATIZE_BY_REFERENCE hook_bool_const_tree_false
  #define LANG_HOOKS_OMP_PREDETERMINED_SHARING lhd_omp_predetermined_sharing
  #define LANG_HOOKS_OMP_REPORT_DECL lhd_pass_through_t
@@ -261,6 +262,7 @@ extern tree lhd_unit_size_without_reusable_padding (tree);
    LANG_HOOKS_WARN_UNUSED_GLOBAL_DECL, \
    LANG_HOOKS_POST_COMPILATION_PARSING_CLEANUPS, \
    LANG_HOOKS_DECL_OK_FOR_SIBCALL, \
+  LANG_HOOKS_OMP_IS_OPTIONAL_ARGUMENT, \
    LANG_HOOKS_OMP_PRIVATIZE_BY_REFERENCE, \
    LANG_HOOKS_OMP_PREDETERMINED_SHARING, \
    LANG_HOOKS_OMP_REPORT_DECL, \
diff --git a/gcc/langhooks.h b/gcc/langhooks.h
index a45579b..9d2714a 100644
--- a/gcc/langhooks.h
+++ b/gcc/langhooks.h
@@ -222,6 +222,9 @@ struct lang_hooks_for_decls
    /* True if this decl may be called via a sibcall.  */
    bool (*ok_for_sibcall) (const_tree);

+  /* True if OpenMP should treat DECL as a Fortran optional argument.  */
+  bool (*omp_is_optional_argument) (const_tree);
+
    /* True if OpenMP should privatize what this DECL points to rather
       than the DECL itself.  */
    bool (*omp_privatize_by_reference) (const_tree);
diff --git a/gcc/omp-general.c b/gcc/omp-general.c
index 8086f9a..1a09dc1 100644
--- a/gcc/omp-general.c
+++ b/gcc/omp-general.c
@@ -48,6 +48,14 @@ omp_find_clause (tree clauses, enum omp_clause_code kind)
    return NULL_TREE;
  }

+/* Return true if DECL is a Fortran optional argument.  */
+
+bool
+omp_is_optional_argument (tree decl)
+{
+  return lang_hooks.decls.omp_is_optional_argument (decl);
+}
+
  /* Return true if DECL is a reference type.  */

  bool
diff --git a/gcc/omp-general.h b/gcc/omp-general.h
index 80d42af..bbaa7b1 100644
--- a/gcc/omp-general.h
+++ b/gcc/omp-general.h
@@ -73,6 +73,7 @@ struct omp_for_data
  #define OACC_FN_ATTRIB "oacc function"

  extern tree omp_find_clause (tree clauses, enum omp_clause_code kind);
+extern bool omp_is_optional_argument (tree decl);
  extern bool omp_is_reference (tree decl);
  extern void omp_adjust_for_condition (location_t loc, enum tree_code *cond_code,
  				      tree *n2, tree v, tree step);
diff --git a/gcc/omp-low.c b/gcc/omp-low.c
index a855c5b..1c7b43b 100644
--- a/gcc/omp-low.c
+++ b/gcc/omp-low.c
@@ -11173,7 +11173,8 @@ lower_omp_target (gimple_stmt_iterator *gsi_p, 
omp_context *ctx)
  	      {
  		gcc_assert (is_gimple_omp_oacc (ctx->stmt));
  		if (omp_is_reference (new_var)
-		    && TREE_CODE (TREE_TYPE (new_var)) != POINTER_TYPE)
+		    && (TREE_CODE (TREE_TYPE (new_var)) != POINTER_TYPE
+		        || DECL_BY_REFERENCE (var)))
  		  {
  		    /* Create a local object to hold the instance
  		       value.  */
@@ -11461,7 +11462,9 @@ lower_omp_target (gimple_stmt_iterator *gsi_p, 
omp_context *ctx)
  	      {
  		gcc_checking_assert (is_gimple_omp_oacc (ctx->stmt));
  		s = TREE_TYPE (ovar);
-		if (TREE_CODE (s) == REFERENCE_TYPE)
+		if (TREE_CODE (s) == REFERENCE_TYPE
+		    || (TREE_CODE (s) == POINTER_TYPE
+			&& omp_is_optional_argument (ovar)))
  		  s = TREE_TYPE (s);
  		s = TYPE_SIZE_UNIT (s);
  	      }
-- 
2.8.1

^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: [PATCH 4/5, OpenACC] Allow optional arguments to be used in the use_device OpenACC clause
  2019-07-12 11:39   ` [PATCH 4/5, OpenACC] Allow optional arguments to be used in the use_device OpenACC clause Kwok Cheung Yeung
@ 2019-07-29 22:42     ` Kwok Cheung Yeung
  2019-07-31 13:13       ` Jakub Jelinek
  0 siblings, 1 reply; 65+ messages in thread
From: Kwok Cheung Yeung @ 2019-07-29 22:42 UTC (permalink / raw)
  To: gcc-patches, fortran, jakub; +Cc: thomas

On 12/07/2019 12:38 pm, Kwok Cheung Yeung wrote:
> This patch fixes a similar situation that occurs with the use_device 
> clause, where the lowering would result in a null dereference if applied 
> to a non-present optional argument. This patch builds a conditional 
> check that skips the dereference if the argument is non-present, and 
> ensures that optional arguments are treated like references.

With the updated patch in part 2 of this series, this patch can be 
simplified slightly by reducing the number of calls to 
omp_is_optional_argument.

Kwok

	gcc/
	* omp-low.c (lower_omp_target): For use_device clauses that take
	optional arguments, generate conditional statements to avoid
	dereferences of non-present arguments.
---
  gcc/omp-low.c | 75 
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
  1 file changed, 73 insertions(+), 2 deletions(-)

diff --git a/gcc/omp-low.c b/gcc/omp-low.c
index 1c7b43b..9c40100 100644
--- a/gcc/omp-low.c
+++ b/gcc/omp-low.c
@@ -11636,9 +11636,40 @@ lower_omp_target (gimple_stmt_iterator *gsi_p, 
omp_context *ctx)
  	      tkind = GOMP_MAP_FIRSTPRIVATE_INT;
  	    type = TREE_TYPE (ovar);
  	    if (TREE_CODE (type) == ARRAY_TYPE)
-	      var = build_fold_addr_expr (var);
+	      {
+		var = build_fold_addr_expr (var);
+		gimplify_assign (x, var, &ilist);
+	      }
  	    else
  	      {
+		tree opt_arg_label;
+		bool optional_arg_p
+		  = TREE_CODE (TREE_TYPE (ovar)) == POINTER_TYPE
+		    && omp_is_optional_argument (ovar);
+
+		if (optional_arg_p)
+		  {
+		    tree null_label
+		      = create_artificial_label (UNKNOWN_LOCATION);
+		    tree notnull_label
+		      = create_artificial_label (UNKNOWN_LOCATION);
+		    opt_arg_label
+		      = create_artificial_label (UNKNOWN_LOCATION);
+		    tree new_x = copy_node (x);
+		    gcond *cond = gimple_build_cond (EQ_EXPR, ovar,
+						     null_pointer_node,
+						     null_label,
+						     notnull_label);
+		    gimple_seq_add_stmt (&ilist, cond);
+		    gimple_seq_add_stmt (&ilist,
+					 gimple_build_label (null_label));
+		    gimplify_assign (new_x, null_pointer_node, &ilist);
+		    gimple_seq_add_stmt (&ilist,
+					 gimple_build_goto (opt_arg_label));
+		    gimple_seq_add_stmt (&ilist,
+					 gimple_build_label (notnull_label));
+		  }
+
  		if (omp_is_reference (ovar))
  		  {
  		    type = TREE_TYPE (type);
@@ -11646,8 +11677,12 @@ lower_omp_target (gimple_stmt_iterator *gsi_p, 
omp_context *ctx)
  		      var = build_simple_mem_ref (var);
  		    var = fold_convert (TREE_TYPE (x), var);
  		  }
+
+		gimplify_assign (x, var, &ilist);
+		if (optional_arg_p)
+		  gimple_seq_add_stmt (&ilist,
+				       gimple_build_label (opt_arg_label));
  	      }
-	    gimplify_assign (x, var, &ilist);
  	    s = size_int (0);
  	    purpose = size_int (map_idx++);
  	    CONSTRUCTOR_APPEND_ELT (vsize, purpose, s);
@@ -11829,11 +11864,43 @@ lower_omp_target (gimple_stmt_iterator *gsi_p, 
omp_context *ctx)
  	      {
  		tree type = TREE_TYPE (var);
  		tree new_var = lookup_decl (var, ctx);
+		tree opt_arg_label = NULL_TREE;
+
  		if (omp_is_reference (var))
  		  {
  		    type = TREE_TYPE (type);
  		    if (TREE_CODE (type) != ARRAY_TYPE)
  		      {
+			if (omp_is_optional_argument (var))
+			  {
+			    tree null_label
+			      = create_artificial_label (UNKNOWN_LOCATION);
+			    tree notnull_label
+			      = create_artificial_label (UNKNOWN_LOCATION);
+			    opt_arg_label
+			      = create_artificial_label (UNKNOWN_LOCATION);
+			    glabel *null_glabel
+			      = gimple_build_label (null_label);
+			    glabel *notnull_glabel
+			      = gimple_build_label (notnull_label);
+			    ggoto *opt_arg_ggoto
+			      = gimple_build_goto (opt_arg_label);
+			    gcond *cond;
+
+			    gimplify_expr (&x, &new_body, NULL, is_gimple_val,
+					   fb_rvalue);
+			    cond = gimple_build_cond (EQ_EXPR, x,
+						      null_pointer_node,
+						      null_label,
+						      notnull_label);
+			    gimple_seq_add_stmt (&new_body, cond);
+			    gimple_seq_add_stmt (&new_body, null_glabel);
+			    gimplify_assign (new_var, null_pointer_node,
+					     &new_body);
+			    gimple_seq_add_stmt (&new_body, opt_arg_ggoto);
+			    gimple_seq_add_stmt (&new_body, notnull_glabel);
+			  }
+
  			tree v = create_tmp_var_raw (type, get_name (var));
  			gimple_add_tmp_var (v);
  			TREE_ADDRESSABLE (v) = 1;
@@ -11850,6 +11917,10 @@ lower_omp_target (gimple_stmt_iterator *gsi_p, 
omp_context *ctx)
  		gimplify_expr (&x, &new_body, NULL, is_gimple_val, fb_rvalue);
  		gimple_seq_add_stmt (&new_body,
  				     gimple_build_assign (new_var, x));
+
+		if (opt_arg_label != NULL_TREE)
+		  gimple_seq_add_stmt (&new_body,
+				       gimple_build_label (opt_arg_label));
  	      }
  	    break;
  	  }
-- 
2.8.1

^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: [PATCH 2/5, OpenACC] Support Fortran optional arguments in the firstprivate clause
  2019-07-29 21:01       ` Kwok Cheung Yeung
@ 2019-07-31 12:54         ` Jakub Jelinek
  2019-10-07  9:26         ` Thomas Schwinge
  1 sibling, 0 replies; 65+ messages in thread
From: Jakub Jelinek @ 2019-07-31 12:54 UTC (permalink / raw)
  To: Kwok Cheung Yeung; +Cc: gcc-patches, fortran, thomas, Tobias Burnus

On Mon, Jul 29, 2019 at 09:55:52PM +0100, Kwok Cheung Yeung wrote:
> +/* True if OpenMP should treat this DECL as an optional argument.  */
> +
> +bool
> +gfc_omp_is_optional_argument (const_tree decl)
> +{
> +  return DECL_LANG_SPECIFIC (decl)
> +	 && GFC_DECL_OPTIONAL_ARGUMENT (decl);

I think this ought to be written as:
  return (DECL_LANG_SPECIFIC (decl)
	  && GFC_DECL_OPTIONAL_ARGUMENT (decl));
because otherwise for emacs users (not me) emacs mishandles it.
Also, I wonder if it shouldn't start with TREE_CODE (decl) == PARM_DECL
check, anything else isn't a dummy argument and so can't be optional.

> +}
> +
>  /* True if OpenMP should privatize what this DECL points to rather
>     than the DECL itself.  */
> 

Otherwise LGTM.

	Jakub

^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: [PATCH 4/5, OpenACC] Allow optional arguments to be used in the use_device OpenACC clause
  2019-07-29 22:42     ` Kwok Cheung Yeung
@ 2019-07-31 13:13       ` Jakub Jelinek
  0 siblings, 0 replies; 65+ messages in thread
From: Jakub Jelinek @ 2019-07-31 13:13 UTC (permalink / raw)
  To: Kwok Cheung Yeung; +Cc: gcc-patches, fortran, thomas

On Mon, Jul 29, 2019 at 10:00:53PM +0100, Kwok Cheung Yeung wrote:
> --- a/gcc/omp-low.c
> +++ b/gcc/omp-low.c
> @@ -11636,9 +11636,40 @@ lower_omp_target (gimple_stmt_iterator *gsi_p,
> omp_context *ctx)
>  	      tkind = GOMP_MAP_FIRSTPRIVATE_INT;
>  	    type = TREE_TYPE (ovar);
>  	    if (TREE_CODE (type) == ARRAY_TYPE)
> -	      var = build_fold_addr_expr (var);
> +	      {
> +		var = build_fold_addr_expr (var);
> +		gimplify_assign (x, var, &ilist);
> +	      }
>  	    else
>  	      {
> +		tree opt_arg_label;
> +		bool optional_arg_p
> +		  = TREE_CODE (TREE_TYPE (ovar)) == POINTER_TYPE
> +		    && omp_is_optional_argument (ovar);

This should be also wrapped in ()s for emacs, like:

		bool optional_arg_p
		  = (TREE_CODE (TREE_TYPE (ovar)) == POINTER_TYPE
		     && omp_is_optional_argument (ovar));

> +
> +		if (optional_arg_p)
> +		  {
> +		    tree null_label
> +		      = create_artificial_label (UNKNOWN_LOCATION);
> +		    tree notnull_label
> +		      = create_artificial_label (UNKNOWN_LOCATION);
> +		    opt_arg_label
> +		      = create_artificial_label (UNKNOWN_LOCATION);
> +		    tree new_x = copy_node (x);

Please use unshare_expr instead of copy_node here.

Otherwise LGTM.

On the OpenMP side this isn't sufficient, because it only
handles mapping clauses, not the data sharing, so I guess I'll need to go
through all data sharing clauses on all constructs, write testcases and see
if what OpenMP spec says (just a general rule):
"If a list item that appears in a directive or clause is an optional dummy argument that is not present,
the directive or clause for that list item is ignored.

If the variable referenced inside a construct is an optional dummy argument that is not present, any
explicitly determined, implicitly determined, or predetermined data-sharing and data-mapping
attribute rules for that variable are ignored. Otherwise, if the variable is an optional dummy
argument that is present, it is present inside the construct."
is handled right.

	Jakub

^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: [PATCH 2/5, OpenACC] Support Fortran optional arguments in the firstprivate clause
  2019-07-29 21:01       ` Kwok Cheung Yeung
  2019-07-31 12:54         ` Jakub Jelinek
@ 2019-10-07  9:26         ` Thomas Schwinge
  2019-10-07 13:16           ` Kwok Cheung Yeung
  1 sibling, 1 reply; 65+ messages in thread
From: Thomas Schwinge @ 2019-10-07  9:26 UTC (permalink / raw)
  To: Kwok Cheung Yeung, Tobias Burnus; +Cc: Jakub Jelinek, gcc-patches, fortran

[-- Attachment #1: Type: text/plain, Size: 1515 bytes --]

Hi Kwok, Tobias!

On 2019-07-29T21:55:52+0100, Kwok Cheung Yeung <kcy@codesourcery.com> wrote:
>  >  		if (omp_is_reference (new_var)
>  > 		    && TREE_CODE (TREE_TYPE (new_var)) != POINTER_TYPE)
>
> As is, this code in lower_omp_target will always reject optional arguments, so 
> it must be changed. This was introduced in commit r261025 (SVN trunk) as a fix 
> for PR 85879, but it also breaks support for arrays in firstprivate, which was 
> probably an unintended side-effect.

Do we have sufficient testsuite coverage for "arrays in firstprivate", in
all languages?


Grüße
 Thomas


> I have found that allowing POINTER_TYPEs 
> that are also DECL_BY_REFERENCE through in this condition allows both optional 
> arguments and arrays to work without regressing the tests in r261025.

> 	* omp-low.c (lower_omp_target): Create temporary for received value
> 	and take the address for new_var if the original variable was a
> 	DECL_BY_REFERENCE.  [...]

> --- a/gcc/omp-low.c
> +++ b/gcc/omp-low.c
> @@ -11173,7 +11173,8 @@ lower_omp_target (gimple_stmt_iterator *gsi_p, 
> omp_context *ctx)
>   	      {
>   		gcc_assert (is_gimple_omp_oacc (ctx->stmt));
>   		if (omp_is_reference (new_var)
> -		    && TREE_CODE (TREE_TYPE (new_var)) != POINTER_TYPE)
> +		    && (TREE_CODE (TREE_TYPE (new_var)) != POINTER_TYPE
> +		        || DECL_BY_REFERENCE (var)))
>   		  {
>   		    /* Create a local object to hold the instance
>   		       value.  */


Grüße
 Thomas

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 658 bytes --]

^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: [PATCH 2/5, OpenACC] Support Fortran optional arguments in the firstprivate clause
  2019-10-07  9:26         ` Thomas Schwinge
@ 2019-10-07 13:16           ` Kwok Cheung Yeung
  0 siblings, 0 replies; 65+ messages in thread
From: Kwok Cheung Yeung @ 2019-10-07 13:16 UTC (permalink / raw)
  To: Thomas Schwinge, Tobias Burnus; +Cc: Jakub Jelinek, gcc-patches, fortran

On 07/10/2019 10:25 am, Thomas Schwinge wrote:
> Hi Kwok, Tobias!
> 
> On 2019-07-29T21:55:52+0100, Kwok Cheung Yeung <kcy@codesourcery.com> wrote:
>>   >  		if (omp_is_reference (new_var)
>>   > 		    && TREE_CODE (TREE_TYPE (new_var)) != POINTER_TYPE)
>>
>> As is, this code in lower_omp_target will always reject optional arguments, so
>> it must be changed. This was introduced in commit r261025 (SVN trunk) as a fix
>> for PR 85879, but it also breaks support for arrays in firstprivate, which was
>> probably an unintended side-effect.
> 
> Do we have sufficient testsuite coverage for "arrays in firstprivate", in
> all languages?
> 

I don't know about other languages, but for Fortran, definitely not. The 
only testcase that exercises this AFAIK is optional-firstprivate.f90 in 
part 5 of this patch series.

Kwok

^ permalink raw reply	[flat|nested] 65+ messages in thread

* [Patch][OpenMP/OpenACC/Fortran] Fix mapping of optional (present|absent) arguments
@ 2019-11-20 13:11       ` Tobias Burnus
  2019-11-29 12:17         ` Tobias Burnus
                           ` (2 more replies)
  0 siblings, 3 replies; 65+ messages in thread
From: Tobias Burnus @ 2019-11-20 13:11 UTC (permalink / raw)
  To: gcc-patches, fortran, Jakub Jelinek, Thomas Schwinge

[-- Attachment #1: Type: text/plain, Size: 1175 bytes --]

This patch does two things regarding explicit and automatical variable 
mapping to offloaded devices:

* Fixes bugs with optional arguments, which are present. They were 
mapped but the mapping had issues causing run-time failures.
* It now also handles absent optional arguments.

Compared to the previous patch set,** I added several OpenMP test cases 
– and fixed the fallout.

Except for trivial changes to libgomp/oacc-mem.c and omp-low.c, all 
changes are in fortran/trans-openmp.c and only affect optional arguments.

The patch was bootstrapped and tested on x86_64-gnu-linux w/o 
offloading-support configured and with nvptx offloading.

Tobias

** Included in the attached patch are the following previously posted 
patches: [1] the trivial libgomp/oacc-mem.c change, [2] only the 
remaining single-line change in omp-low.c, [3] the trans-openmp.c 
changes (which had to be modified+extended), and [5] the test cases. 
([2] and [4] are already in GCC 10.) See: 
https://gcc.gnu.org/ml/gcc-patches/2019-07/threads.html#00960 for the 
original patches.

PS: For full OpenMP support, (absent) optional arguments also needed to 
be handled for data-share clauses.


[-- Attachment #2: optional-absent-map-v6.diff --]
[-- Type: text/x-patch, Size: 61056 bytes --]

2019-10-20  Tobias Burnus  <tobias@codesourcery.com>
	    Kwok Cheung Yeung <kcy@codesourcery.com>

	gcc/fortran/
	* trans-openmp.c (gfc_build_conditional_assign, 
	gfc_build_conditional_assign_expr): New static functions.
	(gfc_omp_finish_clause, gfc_trans_omp_clauses): Handle mapping of
	absent optional arguments and fix mapping of present optional args.

	gcc/
	* omp-low.c (lower_omp_target): For optional arguments, deref once
	more to obtain the type.

	libgomp/
	* oacc-mem.c (update_dev_host, gomp_acc_insert_pointer): Just return
	if input it a NULL pointer.
	* testsuite/libgomp.oacc-c-c++-common/lib-43.c: Remove; dependent on
	diagnostic of NULL pointer.
	* testsuite/libgomp.oacc-c-c++-common/lib-47.c: Ditto.
	* testsuite/libgomp.fortran/optional-map.f90: New.
	* testsuite/libgomp.fortran/use_device_addr-1.f90
	(test_dummy_opt_callee_1_absent): New.
	(test_dummy_opt_call_1): Call it.
	* testsuite/libgomp.fortran/use_device_addr-2.f90: Likewise.
	* testsuite/libgomp.fortran/use_device_addr-3.f90: Likewise.
	* testsuite/libgomp.fortran/use_device_addr-4.f90: Likewise.
	* testsuite/libgomp.oacc-fortran/optional-cache.f95: New.
	* testsuite/libgomp.oacc-fortran/optional-data-copyin-by-value.f90: New.
	* testsuite/libgomp.oacc-fortran/optional-data-copyin.f90: New.
	* testsuite/libgomp.oacc-fortran/optional-data-copyout.f90: New.
	* testsuite/libgomp.oacc-fortran/optional-data-enter-exit.f90: New.
	* testsuite/libgomp.oacc-fortran/optional-declare.f90: New.
	* testsuite/libgomp.oacc-fortran/optional-firstprivate.f90: New.
	* testsuite/libgomp.oacc-fortran/optional-host_data.f90: New.
	* testsuite/libgomp.oacc-fortran/optional-nested-calls.f90: New.
	* testsuite/libgomp.oacc-fortran/optional-private.f90: New.
	* testsuite/libgomp.oacc-fortran/optional-reduction.f90: New.
	* testsuite/libgomp.oacc-fortran/optional-update-device.f90: New.
	* testsuite/libgomp.oacc-fortran/optional-update-host.f90: New.

 gcc/fortran/trans-openmp.c                                               | 224 ++++++++++++++++++++++++++++++++++++---
 gcc/omp-low.c                                                            |   3 +-
 libgomp/oacc-mem.c                                                       |   9 ++
 libgomp/testsuite/libgomp.fortran/optional-map.f90                       | 119 +++++++++++++++++++++
 libgomp/testsuite/libgomp.fortran/use_device_addr-1.f90                  |  36 +++++++
 libgomp/testsuite/libgomp.fortran/use_device_addr-2.f90                  |  36 +++++++
 libgomp/testsuite/libgomp.fortran/use_device_addr-3.f90                  |  27 +++++
 libgomp/testsuite/libgomp.fortran/use_device_addr-4.f90                  |  27 +++++
 libgomp/testsuite/libgomp.oacc-c-c++-common/lib-43.c                     |  51 ---------
 libgomp/testsuite/libgomp.oacc-c-c++-common/lib-47.c                     |  49 ---------
 libgomp/testsuite/libgomp.oacc-fortran/optional-cache.f95                |  23 ++++
 libgomp/testsuite/libgomp.oacc-fortran/optional-data-copyin-by-value.f90 |  29 +++++
 libgomp/testsuite/libgomp.oacc-fortran/optional-data-copyin.f90          | 140 ++++++++++++++++++++++++
 libgomp/testsuite/libgomp.oacc-fortran/optional-data-copyout.f90         |  96 +++++++++++++++++
 libgomp/testsuite/libgomp.oacc-fortran/optional-data-enter-exit.f90      |  91 ++++++++++++++++
 libgomp/testsuite/libgomp.oacc-fortran/optional-declare.f90              |  87 +++++++++++++++
 libgomp/testsuite/libgomp.oacc-fortran/optional-firstprivate.f90         | 112 ++++++++++++++++++++
 libgomp/testsuite/libgomp.oacc-fortran/optional-host_data.f90            |  39 +++++++
 libgomp/testsuite/libgomp.oacc-fortran/optional-nested-calls.f90         | 135 +++++++++++++++++++++++
 libgomp/testsuite/libgomp.oacc-fortran/optional-private.f90              | 115 ++++++++++++++++++++
 libgomp/testsuite/libgomp.oacc-fortran/optional-reduction.f90            |  69 ++++++++++++
 libgomp/testsuite/libgomp.oacc-fortran/optional-update-device.f90        | 121 +++++++++++++++++++++
 libgomp/testsuite/libgomp.oacc-fortran/optional-update-host.f90          | 115 ++++++++++++++++++++
 23 files changed, 1640 insertions(+), 113 deletions(-)

diff --git a/gcc/fortran/trans-openmp.c b/gcc/fortran/trans-openmp.c
index d9dfcabc65e..77bc9120d85 100644
--- a/gcc/fortran/trans-openmp.c
+++ b/gcc/fortran/trans-openmp.c
@@ -1175,6 +1175,64 @@ gfc_omp_clause_dtor (tree clause, tree decl)
   return tem;
 }
 
+/* Build a conditional expression in BLOCK.  If COND_VAL is not
+   null, then the block THEN_B is executed, otherwise ELSE_VAL
+   is assigned to VAL.  */
+
+static void
+gfc_build_conditional_assign (stmtblock_t *block,
+			      tree val,
+			      tree cond_val,
+			      tree then_b,
+			      tree else_val)
+{
+  stmtblock_t cond_block;
+  tree cond, else_b = NULL_TREE;
+  tree val_ty = TREE_TYPE (val);
+
+  if (else_val)
+    {
+      gfc_init_block (&cond_block);
+      gfc_add_modify (&cond_block, val, fold_convert (val_ty, else_val));
+      else_b = gfc_finish_block (&cond_block);
+    }
+  cond = fold_build2_loc (input_location, NE_EXPR,
+			  logical_type_node,
+			  cond_val, null_pointer_node);
+  gfc_add_expr_to_block (block,
+			 build3_loc (input_location,
+				     COND_EXPR,
+				     void_type_node,
+				     cond, then_b,
+				     else_b));
+}
+
+/* Build a conditional expression in BLOCK, returning a temporary
+   variable containing the result.  If COND_VAL is not null, then
+   THEN_VAL will be assigned to the variable, otherwise ELSE_VAL
+   is assigned.
+ */
+
+static tree
+gfc_build_conditional_assign_expr (stmtblock_t *block,
+				   tree cond_val,
+				   tree then_val,
+				   tree else_val)
+{
+  tree val;
+  tree val_ty = TREE_TYPE (then_val);
+  stmtblock_t cond_block;
+
+  val = create_tmp_var (val_ty);
+
+  gfc_init_block (&cond_block);
+  gfc_add_modify (&cond_block, val, then_val);
+  tree then_b = gfc_finish_block (&cond_block);
+
+  gfc_build_conditional_assign (block, val, cond_val, then_b, else_val);
+
+  return val;
+}
 
 void
 gfc_omp_finish_clause (tree c, gimple_seq *pre_p)
@@ -1199,6 +1257,8 @@ gfc_omp_finish_clause (tree c, gimple_seq *pre_p)
     }
 
   tree c2 = NULL_TREE, c3 = NULL_TREE, c4 = NULL_TREE;
+  tree present = gfc_omp_is_optional_argument (decl)
+		 ? gfc_omp_check_optional_argument (decl, true) : NULL_TREE;
   if (POINTER_TYPE_P (TREE_TYPE (decl)))
     {
       if (!gfc_omp_privatize_by_reference (decl)
@@ -1213,8 +1273,30 @@ gfc_omp_finish_clause (tree c, gimple_seq *pre_p)
       OMP_CLAUSE_DECL (c4) = decl;
       OMP_CLAUSE_SIZE (c4) = size_int (0);
       decl = build_fold_indirect_ref (decl);
-      OMP_CLAUSE_DECL (c) = decl;
-      OMP_CLAUSE_SIZE (c) = NULL_TREE;
+      if (present
+	  && (GFC_DECL_GET_SCALAR_POINTER (orig_decl)
+	      || GFC_DECL_GET_SCALAR_ALLOCATABLE (orig_decl)))
+	{
+	  c2 = build_omp_clause (input_location, OMP_CLAUSE_MAP);
+	  OMP_CLAUSE_SET_MAP_KIND (c2, GOMP_MAP_POINTER);
+	  OMP_CLAUSE_DECL (c2) = decl;
+	  OMP_CLAUSE_SIZE (c2) = size_int (0);
+
+	  stmtblock_t block;
+	  gfc_start_block (&block);
+	  tree ptr = decl;
+	  ptr = gfc_build_conditional_assign_expr (&block, present, decl,
+						   null_pointer_node);
+	  gimplify_and_add (gfc_finish_block (&block), pre_p);
+	  ptr = build_fold_indirect_ref (ptr);
+	  OMP_CLAUSE_DECL (c) = ptr;
+	  OMP_CLAUSE_SIZE (c) = TYPE_SIZE_UNIT (TREE_TYPE (ptr));
+	}
+      else
+	{
+	  OMP_CLAUSE_DECL (c) = decl;
+	  OMP_CLAUSE_SIZE (c) = NULL_TREE;
+	}
       if (TREE_CODE (TREE_TYPE (orig_decl)) == REFERENCE_TYPE
 	  && (GFC_DECL_GET_SCALAR_POINTER (orig_decl)
 	      || GFC_DECL_GET_SCALAR_ALLOCATABLE (orig_decl)))
@@ -1232,17 +1314,43 @@ gfc_omp_finish_clause (tree c, gimple_seq *pre_p)
       stmtblock_t block;
       gfc_start_block (&block);
       tree type = TREE_TYPE (decl);
-      tree ptr = gfc_conv_descriptor_data_get (decl);
+      tree ptr;
+
+      if (present)
+	ptr = gfc_build_conditional_assign_expr (
+		&block, present,
+		gfc_conv_descriptor_data_get (decl),
+		null_pointer_node);
+      else
+	ptr = gfc_conv_descriptor_data_get (decl);
       ptr = fold_convert (build_pointer_type (char_type_node), ptr);
       ptr = build_fold_indirect_ref (ptr);
       OMP_CLAUSE_DECL (c) = ptr;
       c2 = build_omp_clause (input_location, OMP_CLAUSE_MAP);
       OMP_CLAUSE_SET_MAP_KIND (c2, GOMP_MAP_TO_PSET);
-      OMP_CLAUSE_DECL (c2) = decl;
+      if (present)
+	{
+	  ptr = create_tmp_var (TREE_TYPE (TREE_OPERAND (decl, 0)));
+	  gfc_add_modify (&block, ptr, TREE_OPERAND (decl, 0));
+
+	  OMP_CLAUSE_DECL (c2) = build_fold_indirect_ref (ptr);
+	}
+      else
+	OMP_CLAUSE_DECL (c2) = decl;
       OMP_CLAUSE_SIZE (c2) = TYPE_SIZE_UNIT (type);
       c3 = build_omp_clause (OMP_CLAUSE_LOCATION (c), OMP_CLAUSE_MAP);
       OMP_CLAUSE_SET_MAP_KIND (c3, GOMP_MAP_POINTER);
-      OMP_CLAUSE_DECL (c3) = gfc_conv_descriptor_data_get (decl);
+      if (present)
+	{
+	  ptr = gfc_conv_descriptor_data_get (decl);
+	  ptr = gfc_build_addr_expr (NULL, ptr);
+	  ptr = gfc_build_conditional_assign_expr (&block, present,
+						   ptr, null_pointer_node);
+	  ptr = build_fold_indirect_ref (ptr);
+	  OMP_CLAUSE_DECL (c3) = ptr;
+	}
+      else
+	OMP_CLAUSE_DECL (c3) = gfc_conv_descriptor_data_get (decl);
       OMP_CLAUSE_SIZE (c3) = size_int (0);
       tree size = create_tmp_var (gfc_array_index_type);
       tree elemsz = TYPE_SIZE_UNIT (gfc_get_element_type (type));
@@ -1268,11 +1376,36 @@ gfc_omp_finish_clause (tree c, gimple_seq *pre_p)
 	  tem = gfc_conv_descriptor_data_get (decl);
 	  tem = fold_convert (pvoid_type_node, tem);
 	  cond = fold_build2_loc (input_location, NE_EXPR,
-				  logical_type_node, tem, null_pointer_node);
+				  boolean_type_node, tem, null_pointer_node);
+	  if (present)
+	    {
+	      tem = fold_build2_loc (input_location, NE_EXPR, boolean_type_node,
+				     present, null_pointer_node);
+	      cond = fold_build2_loc (input_location, TRUTH_ANDIF_EXPR,
+				      boolean_type_node, tem, cond);
+	    }
 	  gfc_add_expr_to_block (&block, build3_loc (input_location, COND_EXPR,
 						     void_type_node, cond,
 						     then_b, else_b));
 	}
+      else if (present)
+	{
+	  stmtblock_t cond_block;
+	  tree then_b;
+
+	  gfc_init_block (&cond_block);
+	  gfc_add_modify (&cond_block, size,
+			  gfc_full_array_size (&cond_block, decl,
+					       GFC_TYPE_ARRAY_RANK (type)));
+	  gfc_add_modify (&cond_block, size,
+			  fold_build2 (MULT_EXPR, gfc_array_index_type,
+				       size, elemsz));
+	  then_b = gfc_finish_block (&cond_block);
+
+	  gfc_build_conditional_assign (&block, size, present, then_b,
+					build_int_cst (gfc_array_index_type,
+						       0));
+	}
       else
 	{
 	  gfc_add_modify (&block, size,
@@ -2252,6 +2385,9 @@ gfc_trans_omp_clauses (stmtblock_t *block, gfc_omp_clauses *clauses,
 		TREE_ADDRESSABLE (decl) = 1;
 	      if (n->expr == NULL || n->expr->ref->u.ar.type == AR_FULL)
 		{
+		  tree present = gfc_omp_is_optional_argument (decl)
+				 ? gfc_omp_check_optional_argument (decl, true)
+				 : NULL_TREE;
 		  if (POINTER_TYPE_P (TREE_TYPE (decl))
 		      && (gfc_omp_privatize_by_reference (decl)
 			  || GFC_DECL_GET_SCALAR_POINTER (decl)
@@ -2284,6 +2420,10 @@ gfc_trans_omp_clauses (stmtblock_t *block, gfc_omp_clauses *clauses,
 		    {
 		      tree type = TREE_TYPE (decl);
 		      tree ptr = gfc_conv_descriptor_data_get (decl);
+		      if (present)
+			ptr = gfc_build_conditional_assign_expr (
+			       block, present, ptr,
+			       null_pointer_node);
 		      ptr = fold_convert (build_pointer_type (char_type_node),
 					  ptr);
 		      ptr = build_fold_indirect_ref (ptr);
@@ -2296,8 +2436,19 @@ gfc_trans_omp_clauses (stmtblock_t *block, gfc_omp_clauses *clauses,
 		      node3 = build_omp_clause (input_location,
 						OMP_CLAUSE_MAP);
 		      OMP_CLAUSE_SET_MAP_KIND (node3, GOMP_MAP_POINTER);
-		      OMP_CLAUSE_DECL (node3)
-			= gfc_conv_descriptor_data_get (decl);
+		      if (present)
+			{
+			  ptr = gfc_conv_descriptor_data_get (decl);
+			  ptr = gfc_build_addr_expr (NULL, ptr);
+			  ptr = gfc_build_conditional_assign_expr (
+				  block, present, ptr,
+				  null_pointer_node);
+			  ptr = build_fold_indirect_ref (ptr);
+			  OMP_CLAUSE_DECL (node3) = ptr;
+			}
+		      else
+			OMP_CLAUSE_DECL (node3)
+			  = gfc_conv_descriptor_data_get (decl);
 		      OMP_CLAUSE_SIZE (node3) = size_int (0);
 
 		      /* We have to check for n->sym->attr.dimension because
@@ -2322,8 +2473,20 @@ gfc_trans_omp_clauses (stmtblock_t *block, gfc_omp_clauses *clauses,
 			  tem = gfc_conv_descriptor_data_get (decl);
 			  tem = fold_convert (pvoid_type_node, tem);
 			  cond = fold_build2_loc (input_location, NE_EXPR,
-						  logical_type_node,
+						  boolean_type_node,
 						  tem, null_pointer_node);
+			  if (present)
+			    {
+			      tree tmp = fold_build2_loc (input_location,
+							  NE_EXPR,
+							  boolean_type_node,
+							  present,
+							  null_pointer_node);
+			      cond = fold_build2_loc (input_location,
+						      TRUTH_ANDIF_EXPR,
+						      boolean_type_node,
+						      tmp, cond);
+			    }
 			  gfc_add_expr_to_block (block,
 						 build3_loc (input_location,
 							     COND_EXPR,
@@ -2333,9 +2496,34 @@ gfc_trans_omp_clauses (stmtblock_t *block, gfc_omp_clauses *clauses,
 			  OMP_CLAUSE_SIZE (node) = size;
 			}
 		      else if (n->sym->attr.dimension)
-			OMP_CLAUSE_SIZE (node)
-			  = gfc_full_array_size (block, decl,
-						 GFC_TYPE_ARRAY_RANK (type));
+			{
+			  stmtblock_t cond_block;
+			  gfc_init_block (&cond_block);
+			  tree size = gfc_full_array_size (&cond_block, decl,
+					GFC_TYPE_ARRAY_RANK (type));
+			  if (present)
+			    {
+			      tree var = gfc_create_var (gfc_array_index_type,
+							 NULL);
+			      tree cond = fold_build2_loc (input_location,
+							   NE_EXPR,
+							   boolean_type_node,
+							   present,
+							   null_pointer_node);
+			      gfc_add_modify (&cond_block, var, size);
+			      gfc_add_expr_to_block (block,
+				build3_loc (input_location, COND_EXPR,
+					    void_type_node, cond,
+					    gfc_finish_block (&cond_block),
+					    NULL_TREE));
+			      OMP_CLAUSE_SIZE (node) = var;
+			    }
+			  else
+			    {
+			      gfc_add_block_to_block (block, &cond_block);
+			      OMP_CLAUSE_SIZE (node) = size;
+			    }
+			}
 		      if (n->sym->attr.dimension)
 			{
 			  tree elemsz
@@ -2346,6 +2534,18 @@ gfc_trans_omp_clauses (stmtblock_t *block, gfc_omp_clauses *clauses,
 					   OMP_CLAUSE_SIZE (node), elemsz);
 			}
 		    }
+		  else if (present
+			   && TREE_CODE (decl) == INDIRECT_REF
+			   && TREE_CODE (TREE_OPERAND (decl, 0))
+				== INDIRECT_REF)
+		    {
+		      /* A single indirectref is handled by the middle end.  */
+		      gcc_assert (!POINTER_TYPE_P (TREE_TYPE (decl)));
+		      decl = TREE_OPERAND (decl, 0);
+		      decl = gfc_build_conditional_assign_expr (
+			       block, present, decl, null_pointer_node);
+		      OMP_CLAUSE_DECL (node) = build_fold_indirect_ref (decl);
+		    }
 		  else
 		    OMP_CLAUSE_DECL (node) = decl;
 		}
diff --git a/gcc/omp-low.c b/gcc/omp-low.c
index 19132f76da2..8d6742e7223 100644
--- a/gcc/omp-low.c
+++ b/gcc/omp-low.c
@@ -11817,7 +11817,8 @@ lower_omp_target (gimple_stmt_iterator *gsi_p, omp_context *ctx)
 	      {
 		gcc_checking_assert (is_gimple_omp_oacc (ctx->stmt));
 		s = TREE_TYPE (ovar);
-		if (TREE_CODE (s) == REFERENCE_TYPE)
+		if (TREE_CODE (s) == REFERENCE_TYPE
+		    || omp_check_optional_argument (ovar, false))
 		  s = TREE_TYPE (s);
 		s = TYPE_SIZE_UNIT (s);
 	      }
diff --git a/libgomp/oacc-mem.c b/libgomp/oacc-mem.c
index 2f271009fb8..e5088014ccc 100644
--- a/libgomp/oacc-mem.c
+++ b/libgomp/oacc-mem.c
@@ -831,6 +831,12 @@ update_dev_host (int is_dev, void *h, size_t s, int async)
   if (acc_dev->capabilities & GOMP_OFFLOAD_CAP_SHARED_MEM)
     return;
 
+  /* Fortran optional arguments that are non-present result in a
+     NULL host address here.  This can safely be ignored as it is
+     not possible to 'update' a non-present optional argument.  */
+  if (h == NULL)
+    return;
+
   acc_prof_info prof_info;
   acc_api_info api_info;
   bool profiling_p = GOACC_PROFILING_SETUP_P (thr, &prof_info, &api_info);
@@ -901,6 +907,9 @@ gomp_acc_insert_pointer (size_t mapnum, void **hostaddrs, size_t *sizes,
   struct goacc_thread *thr = goacc_thread ();
   struct gomp_device_descr *acc_dev = thr->dev;
 
+  if (*hostaddrs == NULL)
+    return;
+
   if (acc_is_present (*hostaddrs, *sizes))
     {
       splay_tree_key n;
diff --git a/libgomp/testsuite/libgomp.fortran/optional-map.f90 b/libgomp/testsuite/libgomp.fortran/optional-map.f90
new file mode 100644
index 00000000000..56f6e59e815
--- /dev/null
+++ b/libgomp/testsuite/libgomp.fortran/optional-map.f90
@@ -0,0 +1,119 @@
+implicit none (type, external)
+call sub()
+call sub2()
+call call_present_1()
+call call_present_2()
+
+contains
+
+subroutine call_present_1()
+  integer :: ii, ival, iarr, iptr, iparr
+  pointer :: iptr, iparr
+  dimension :: iarr(2), iparr(:)
+  allocate(iptr,iparr(2))
+  ii = 101
+  ival = 102
+  iptr = 103
+  iarr = 104
+  iparr = 105
+  call sub_present(ii, ival, iarr, iptr, iparr)
+  deallocate(iptr,iparr)
+end subroutine
+
+subroutine call_present_2()
+  integer :: ii, ival, iarr, iptr, iparr
+  pointer :: iptr, iparr
+  dimension :: iarr(2), iparr(:)
+  allocate(iptr,iparr(2))
+  ii = 201
+  ival = 202
+  iptr = 203
+  iarr = 204
+  iparr = 205
+  call sub2_present(ii, ival, iarr, iptr, iparr)
+  deallocate(iptr,iparr)
+end subroutine
+
+subroutine sub(ii, ival, iarr, iptr, iparr)
+  integer, optional :: ii, ival, iarr, iptr, iparr
+  pointer :: iptr, iparr
+  dimension :: iarr(:), iparr(:)
+  value :: ival
+  integer :: err
+  err = 42
+  !$omp target map(ii, ival, iarr, iptr, iparr, err)
+  if (present(ii)) then
+    ii = iptr + ival
+    iarr = iparr
+  else
+    err = 0
+  end if
+  if (present(ii)) err = 1
+  if (present(ival)) err = 2
+  if (present(iarr)) err = 3
+  if (present(iptr)) err = 4
+  if (present(iparr)) err = 5
+  !$omp end target
+  if (err /= 0) stop 1
+end subroutine sub
+
+subroutine sub2(ii, ival, iarr, iptr, iparr)
+  integer, optional :: ii, ival, iarr, iptr, iparr
+  pointer :: iptr, iparr
+  dimension :: iarr(:), iparr(:)
+  value :: ival
+  integer :: err(1) ! otherwise, implied defaultmap is firstprivate
+  err(1) = 42
+  !$omp target  ! automatic mapping with implied defaultmap(tofrom) 
+  if (present(ii)) then
+    ii = iptr + ival
+    iarr = iparr
+  else
+    err(1) = 0
+  end if
+  if (present(ii)) err(1) = 1
+  if (present(ival)) err(1) = 2
+  if (present(iarr)) err(1) = 3
+  if (present(iptr)) err(1) = 4
+  if (present(iparr)) err(1) = 5
+  !$omp end target
+  if (err(1) /= 0) stop 2
+end subroutine sub2
+
+subroutine sub_present(ii, ival, iarr, iptr, iparr)
+  integer, optional :: ii, ival, iarr, iptr, iparr
+  pointer :: iptr, iparr
+  dimension :: iarr(:), iparr(:)
+  value :: ival
+  integer :: err
+  err = 42
+  !$omp target map(ii, ival, iarr, iptr, iparr, err)
+  if (.not.present(ii)) err = 1
+  if (.not.present(ival)) err = 2
+  if (.not.present(iarr)) err = 3
+  if (.not.present(iptr)) err = 4
+  if (.not.present(iparr)) err = 5
+  err = err - 42 - 101-102-103-104-105 + ii+ival+iarr(2)+iptr+iparr(2)
+  !$omp end target
+  if (err /= 0) stop 3
+end subroutine sub_present
+
+subroutine sub2_present(ii, ival, iarr, iptr, iparr)
+  integer, optional :: ii, ival, iarr, iptr, iparr
+  pointer :: iptr, iparr
+  dimension :: iarr(:), iparr(:)
+  value :: ival
+  integer :: err(1) ! otherwise, implied defaultmap is firstprivate
+  err(1) = 53
+  !$omp target  ! automatic mapping with implied defaultmap(tofrom) 
+  ! Note: OpenMP 4.5's 'defaultmap' is not yet supported, PR 92568
+  if (.not.present(ii)) err = 1
+  if (.not.present(ival)) err = 2
+  if (.not.present(iarr)) err = 3
+  if (.not.present(iptr)) err = 4
+  if (.not.present(iparr)) err = 5
+  err = err - 53 - 201-202-203-204-205 + ii+ival+iarr(2)+iptr+iparr(2)
+  !$omp end target
+  if (err(1) /= 0) stop 4
+end subroutine sub2_present
+end
diff --git a/libgomp/testsuite/libgomp.fortran/use_device_addr-1.f90 b/libgomp/testsuite/libgomp.fortran/use_device_addr-1.f90
index 94ac76f5700..0254f2dc196 100644
--- a/libgomp/testsuite/libgomp.fortran/use_device_addr-1.f90
+++ b/libgomp/testsuite/libgomp.fortran/use_device_addr-1.f90
@@ -472,6 +472,7 @@ contains
      hh = 88.0_c_double
 
      call test_dummy_opt_callee_1(aa, bb, cc, dd, ee, ff, gg, hh, N)
+     call test_dummy_opt_callee_1_absent(N=N)
      deallocate(ee, ff) ! pointers, only
   end subroutine test_dummy_opt_call_1
 
@@ -527,6 +528,41 @@ contains
      if (any(abs(3.0_c_double * gg - hh) > 10.0_c_double * epsilon(gg))) stop 72
   end subroutine test_dummy_opt_callee_1
 
+  subroutine test_dummy_opt_callee_1_absent(aa, bb, cc, dd, ee, ff, gg, hh, N)
+     ! scalars
+     real(c_double), optional, target :: aa, bb
+     real(c_double), optional, target, allocatable :: cc, dd
+     real(c_double), optional, pointer :: ee, ff
+
+     ! non-descriptor arrays
+     real(c_double), optional, target :: gg(N), hh(N)
+     integer, value :: N
+
+     integer :: err
+
+     ! All shall be absent
+     if (present(aa) .or. present(bb)) stop 243
+     if (present(cc) .or. present(dd)) stop 244
+     if (present(ee) .or. present(ff)) stop 245
+     if (present(gg) .or. present(hh)) stop 246
+
+     !$omp target data map(to:aa) map(from:bb) use_device_addr(aa,bb)
+     if (present(aa) .or. present(bb)) stop 247
+     !$omp end target data
+
+     !$omp target data map(to:cc) map(from:dd) use_device_addr(cc,dd)
+     if (present(cc) .or. present(dd)) stop 248
+     !$omp end target data
+
+     !$omp target data map(to:ee) map(from:ff) use_device_addr(ee,ff)
+     if (present(ee) .or. present(ff)) stop 249
+     !$omp end target data
+
+     !$omp target data map(to:gg) map(from:hh) use_device_addr(gg,hh)
+     if (present(gg) .or. present(hh)) stop 250
+     !$omp end target data
+  end subroutine test_dummy_opt_callee_1_absent
+
   ! Save device ptr - and recall pointer
   subroutine test_dummy_opt_call_2()
      integer, parameter :: N = 1000
diff --git a/libgomp/testsuite/libgomp.fortran/use_device_addr-2.f90 b/libgomp/testsuite/libgomp.fortran/use_device_addr-2.f90
index d6c5a672370..3dd1f90f04c 100644
--- a/libgomp/testsuite/libgomp.fortran/use_device_addr-2.f90
+++ b/libgomp/testsuite/libgomp.fortran/use_device_addr-2.f90
@@ -472,6 +472,7 @@ contains
      hh = 88.0_c_float
 
      call test_dummy_opt_callee_1(aa, bb, cc, dd, ee, ff, gg, hh, N)
+     call test_dummy_opt_callee_1_absent(N=N)
      deallocate(ee, ff) ! pointers, only
   end subroutine test_dummy_opt_call_1
 
@@ -527,6 +528,41 @@ contains
      if (any(abs(3.0_c_float * gg - hh) > 10.0_c_float * epsilon(gg))) stop 72
   end subroutine test_dummy_opt_callee_1
 
+  subroutine test_dummy_opt_callee_1_absent(aa, bb, cc, dd, ee, ff, gg, hh, N)
+     ! scalars
+     real(c_float), optional, target :: aa, bb
+     real(c_float), optional, target, allocatable :: cc, dd
+     real(c_float), optional, pointer :: ee, ff
+
+     ! non-descriptor arrays
+     real(c_float), optional, target :: gg(N), hh(N)
+     integer, value :: N
+
+     integer :: err
+
+     ! All shall be absent
+     if (present(aa) .or. present(bb)) stop 243
+     if (present(cc) .or. present(dd)) stop 244
+     if (present(ee) .or. present(ff)) stop 245
+     if (present(gg) .or. present(hh)) stop 246
+
+     !$omp target data map(to:aa) map(from:bb) use_device_addr(aa,bb)
+     if (present(aa) .or. present(bb)) stop 247
+     !$omp end target data
+
+     !$omp target data map(to:cc) map(from:dd) use_device_addr(cc,dd)
+     if (present(cc) .or. present(dd)) stop 248
+     !$omp end target data
+
+     !$omp target data map(to:ee) map(from:ff) use_device_addr(ee,ff)
+     if (present(ee) .or. present(ff)) stop 249
+     !$omp end target data
+
+     !$omp target data map(to:gg) map(from:hh) use_device_addr(gg,hh)
+     if (present(gg) .or. present(hh)) stop 250
+     !$omp end target data
+  end subroutine test_dummy_opt_callee_1_absent
+
   ! Save device ptr - and recall pointer
   subroutine test_dummy_opt_call_2()
      integer, parameter :: N = 1000
diff --git a/libgomp/testsuite/libgomp.fortran/use_device_addr-3.f90 b/libgomp/testsuite/libgomp.fortran/use_device_addr-3.f90
index 5c42bee718c..82cf9ac8070 100644
--- a/libgomp/testsuite/libgomp.fortran/use_device_addr-3.f90
+++ b/libgomp/testsuite/libgomp.fortran/use_device_addr-3.f90
@@ -290,6 +290,7 @@ contains
      ff = 66.0_c_double
 
      call test_dummy_opt_callee_1(aa, bb, cc, dd, ee, ff, N)
+     call test_dummy_opt_callee_1_absent(N=N)
      deallocate(ee, ff) ! pointers, only
   end subroutine test_dummy_opt_call_1
 
@@ -336,6 +337,32 @@ contains
      if (any(abs(3.0_c_double * ee - ff) > 10.0_c_double * epsilon(ee))) stop 1
   end subroutine test_dummy_opt_callee_1
 
+  subroutine test_dummy_opt_callee_1_absent(aa, bb, cc, dd, ee, ff, N)
+     ! scalars
+     real(c_double), optional, target :: aa(:), bb(:)
+     real(c_double), optional, target, allocatable :: cc(:), dd(:)
+     real(c_double), optional, pointer :: ee(:), ff(:)
+
+     integer, value :: N
+
+     ! All shall be absent
+     if (present(aa) .or. present(bb)) stop 1
+     if (present(cc) .or. present(dd)) stop 1
+     if (present(ee) .or. present(ff)) stop 1
+
+     !$omp target data map(to:aa) map(from:bb) use_device_addr(aa,bb)
+     if (present(aa) .or. present(bb)) stop 1
+     !$omp end target data
+
+     !$omp target data map(to:cc) map(from:dd) use_device_addr(cc,dd)
+     if (present(cc) .or. present(dd)) stop 1
+     !$omp end target data
+
+     !$omp target data map(to:ee) map(from:ff) use_device_addr(ee,ff)
+     if (present(ee) .or. present(ff)) stop 1
+     !$omp end target data
+  end subroutine test_dummy_opt_callee_1_absent
+
   ! Save device ptr - and recall pointer
   subroutine test_dummy_opt_call_2()
      integer, parameter :: N = 1000
diff --git a/libgomp/testsuite/libgomp.fortran/use_device_addr-4.f90 b/libgomp/testsuite/libgomp.fortran/use_device_addr-4.f90
index 5e66a79da90..d17249de2bc 100644
--- a/libgomp/testsuite/libgomp.fortran/use_device_addr-4.f90
+++ b/libgomp/testsuite/libgomp.fortran/use_device_addr-4.f90
@@ -290,6 +290,7 @@ contains
      ff = 66.0_c_float
 
      call test_dummy_opt_callee_1(aa, bb, cc, dd, ee, ff, N)
+     call test_dummy_opt_callee_1_absent(N=N)
      deallocate(ee, ff) ! pointers, only
   end subroutine test_dummy_opt_call_1
 
@@ -336,6 +337,32 @@ contains
      if (any(abs(3.0_c_float * ee - ff) > 10.0_c_float * epsilon(ee))) stop 1
   end subroutine test_dummy_opt_callee_1
 
+  subroutine test_dummy_opt_callee_1_absent(aa, bb, cc, dd, ee, ff, N)
+     ! scalars
+     real(c_float), optional, target :: aa(:), bb(:)
+     real(c_float), optional, target, allocatable :: cc(:), dd(:)
+     real(c_float), optional, pointer :: ee(:), ff(:)
+
+     integer, value :: N
+
+     ! All shall be absent
+     if (present(aa) .or. present(bb)) stop 1
+     if (present(cc) .or. present(dd)) stop 1
+     if (present(ee) .or. present(ff)) stop 1
+
+     !$omp target data map(to:aa) map(from:bb) use_device_addr(aa,bb)
+     if (present(aa) .or. present(bb)) stop 1
+     !$omp end target data
+
+     !$omp target data map(to:cc) map(from:dd) use_device_addr(cc,dd)
+     if (present(cc) .or. present(dd)) stop 1
+     !$omp end target data
+
+     !$omp target data map(to:ee) map(from:ff) use_device_addr(ee,ff)
+     if (present(ee) .or. present(ff)) stop 1
+     !$omp end target data
+  end subroutine test_dummy_opt_callee_1_absent
+
   ! Save device ptr - and recall pointer
   subroutine test_dummy_opt_call_2()
      integer, parameter :: N = 1000
diff --git a/libgomp/testsuite/libgomp.oacc-c-c++-common/lib-43.c b/libgomp/testsuite/libgomp.oacc-c-c++-common/lib-43.c
deleted file mode 100644
index 5db29124e9e..00000000000
--- a/libgomp/testsuite/libgomp.oacc-c-c++-common/lib-43.c
+++ /dev/null
@@ -1,51 +0,0 @@
-/* Exercise acc_update_device with a NULL data address on nvidia targets.  */
-
-/* { dg-do run { target openacc_nvidia_accel_selected } } */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <openacc.h>
-
-int
-main (int argc, char **argv)
-{
-  const int N = 256;
-  int i;
-  unsigned char *h;
-  void *d;
-
-  h = (unsigned char *) malloc (N);
-
-  for (i = 0; i < N; i++)
-    {
-      h[i] = i;
-    }
-
-  d = acc_copyin (h, N);
-  if (!d)
-    abort ();
-
-  for (i = 0; i < N; i++)
-    {
-      h[i] = 0xab;
-    }
-
-  fprintf (stderr, "CheCKpOInT\n");
-  acc_update_device (0, N);
-
-  acc_copyout (h, N);
-
-  for (i = 0; i < N; i++)
-    {
-      if (h[i] != 0xab)
-	abort ();
-    }
-
-  free (h);
-
-  return 0;
-}
-
-/* { dg-output "CheCKpOInT(\n|\r\n|\r).*" } */
-/* { dg-output "\\\[\[^\n\r]*,256\\\] is not mapped" } */
-/* { dg-shouldfail "" } */
diff --git a/libgomp/testsuite/libgomp.oacc-c-c++-common/lib-47.c b/libgomp/testsuite/libgomp.oacc-c-c++-common/lib-47.c
deleted file mode 100644
index c2140429cb1..00000000000
--- a/libgomp/testsuite/libgomp.oacc-c-c++-common/lib-47.c
+++ /dev/null
@@ -1,49 +0,0 @@
-/* Exercise acc_update_self with a NULL data mapping on nvidia targets.  */
-
-/* { dg-do run { target openacc_nvidia_accel_selected } } */
-
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-#include <openacc.h>
-
-int
-main (int argc, char **argv)
-{
-  const int N = 256;
-  int i;
-  unsigned char *h;
-  void *d;
-
-  h = (unsigned char *) malloc (N);
-
-  for (i = 0; i < N; i++)
-    {
-      h[i] = i;
-    }
-
-  d = acc_copyin (h, N);
-  if (!d)
-    abort ();
-
-  memset (&h[0], 0, N);
-
-  fprintf (stderr, "CheCKpOInT\n");
-  acc_update_self (0, N);
-
-  for (i = 0; i < N; i++)
-    {
-      if (h[i] != i)
-	abort ();
-    }
-
-  acc_delete (h, N);
-
-  free (h);
-
-  return 0;
-}
-
-/* { dg-output "CheCKpOInT(\n|\r\n|\r).*" } */
-/* { dg-output "\\\[\[^\n\r]*,256\\\] is not mapped" } */
-/* { dg-shouldfail "" } */
diff --git a/libgomp/testsuite/libgomp.oacc-fortran/optional-cache.f95 b/libgomp/testsuite/libgomp.oacc-fortran/optional-cache.f95
new file mode 100644
index 00000000000..00f7472ae6e
--- /dev/null
+++ b/libgomp/testsuite/libgomp.oacc-fortran/optional-cache.f95
@@ -0,0 +1,23 @@
+! Test that the cache directives work with optional arguments.  The effect
+! of giving a non-present argument to the cache directive is not tested as
+! it is undefined.  The test is based on gfortran.dg/goacc/cache-1.f95.
+
+! { dg-additional-options "-std=f2008" }
+
+program cache_test
+  implicit none
+  integer :: d(10), e(7,13)
+
+  call do_test(d, e)
+contains
+  subroutine do_test(d, e)
+    integer, optional :: d(10), e(7,13)
+    integer :: i
+    do concurrent (i=1:5)
+      !$acc cache (d(1:3))
+      !$acc cache (d(i:i+2))
+      !$acc cache (e(1:3,2:4))
+      !$acc cache (e(i:i+2,i+1:i+3))
+    enddo
+  end
+end
diff --git a/libgomp/testsuite/libgomp.oacc-fortran/optional-data-copyin-by-value.f90 b/libgomp/testsuite/libgomp.oacc-fortran/optional-data-copyin-by-value.f90
new file mode 100644
index 00000000000..5cadeed44b4
--- /dev/null
+++ b/libgomp/testsuite/libgomp.oacc-fortran/optional-data-copyin-by-value.f90
@@ -0,0 +1,29 @@
+! Test OpenACC data regions with optional arguments passed by value.
+
+! { dg-do run }
+
+program test
+  implicit none
+
+  integer :: res
+
+  if (foo(27) .ne. 27) stop 1
+  if (foo(16, 18) .ne. 288) stop 1
+contains
+  function foo(x, y)
+    integer, value :: x
+    integer, value, optional :: y
+    integer :: res, foo
+
+    !$acc data copyin(x, y) copyout(res)
+    !$acc parallel
+    res = x
+    if (present(y)) then
+      res = res * y
+    end if
+    !$acc end parallel
+    !$acc end data
+
+    foo = res
+  end function foo
+end program test
diff --git a/libgomp/testsuite/libgomp.oacc-fortran/optional-data-copyin.f90 b/libgomp/testsuite/libgomp.oacc-fortran/optional-data-copyin.f90
new file mode 100644
index 00000000000..a30908d61a5
--- /dev/null
+++ b/libgomp/testsuite/libgomp.oacc-fortran/optional-data-copyin.f90
@@ -0,0 +1,140 @@
+! Test OpenACC data regions with a copy-in of optional arguments.
+
+! { dg-do run }
+
+program test
+  implicit none
+
+  integer, parameter :: n = 64
+  integer :: i
+  integer :: a_int, b_int, c_int, res_int
+  integer :: a_arr(n), b_arr(n), c_arr(n), res_arr(n)
+  integer, allocatable :: a_alloc(:), b_alloc(:), c_alloc(:), res_alloc(:)
+
+  a_int = 7
+  b_int = 3
+  c_int = 11
+
+  call test_int(res_int, a_int)
+  if (res_int .ne. a_int) stop 1
+
+  call test_int(res_int, a_int, b_int)
+  if (res_int .ne. a_int * b_int) stop 2
+
+  call test_int(res_int, a_int, b_int, c_int)
+  if (res_int .ne. a_int * b_int + c_int) stop 3
+
+  do i = 1, n
+    a_arr(i) = i
+    b_arr(i) = n - i + 1
+    c_arr(i) = i * 3
+  end do
+
+  call test_array(res_arr, a_arr)
+  do i = 1, n
+    if (res_arr(i) .ne. a_arr(i)) stop 4
+  end do
+
+  call test_array(res_arr, a_arr, b_arr)
+  do i = 1, n
+    if (res_arr(i) .ne. a_arr(i) * b_arr(i)) stop 5
+  end do
+
+  call test_array(res_arr, a_arr, b_arr, c_arr)
+  do i = 1, n
+    if (res_arr(i) .ne. a_arr(i) * b_arr(i) + c_arr(i)) stop 6
+  end do
+
+  allocate (a_alloc(n))
+  allocate (b_alloc(n))
+  allocate (c_alloc(n))
+  allocate (res_alloc(n))
+
+  do i = 1, n
+    a_alloc(i) = i
+    b_alloc(i) = n - i + 1
+    c_alloc(i) = i * 3
+  end do
+
+  call test_allocatable(res_alloc, a_alloc)
+  do i = 1, n
+    if (res_alloc(i) .ne. a_alloc(i)) stop 7
+  end do
+
+  call test_allocatable(res_alloc, a_alloc, b_alloc)
+  do i = 1, n
+    if (res_alloc(i) .ne. a_alloc(i) * b_alloc(i)) stop 8
+  end do
+
+  call test_allocatable(res_alloc, a_alloc, b_alloc, c_alloc)
+  do i = 1, n
+    if (res_alloc(i) .ne. a_alloc(i) * b_alloc(i) + c_alloc(i)) stop 9
+  end do
+
+  deallocate (a_alloc)
+  deallocate (b_alloc)
+  deallocate (c_alloc)
+  deallocate (res_alloc)
+contains
+  subroutine test_int(res, a, b, c)
+    integer :: res
+    integer :: a
+    integer, optional :: b, c
+
+    !$acc data copyin(a, b, c) copyout(res)
+    !$acc parallel
+    res = a
+
+    if (present(b)) res = res * b
+
+    if (present(c)) res = res + c
+    !$acc end parallel
+    !$acc end data
+  end subroutine test_int
+
+  subroutine test_array(res, a, b, c)
+    integer :: res(n)
+    integer :: a(n)
+    integer, optional :: b(n), c(n)
+
+    !$acc data copyin(a, b, c) copyout(res)
+    !$acc parallel loop
+    do i = 1, n
+      res(i) = a(i)
+    end do
+
+    !$acc parallel loop
+    do i = 1, n
+      if (present(b)) res(i) = res(i) * b(i)
+    end do
+
+    !$acc parallel loop
+    do i = 1, n
+      if (present(c)) res(i) = res(i) + c(i)
+    end do
+    !$acc end data
+  end subroutine test_array
+
+  subroutine test_allocatable(res, a, b, c)
+    integer, allocatable :: res(:)
+    integer, allocatable  :: a(:)
+    integer, allocatable, optional :: b(:), c(:)
+
+    !$acc data copyin(a, b, c) copyout(res)
+    !$acc parallel loop
+    do i = 1, n
+      res(i) = a(i)
+    end do
+
+    !$acc parallel loop
+    do i = 1, n
+      if (present(b)) res(i) = res(i) * b(i)
+    end do
+
+    !$acc parallel loop
+    do i = 1, n
+      if (present(c)) res(i) = res(i) + c(i)
+    end do
+    !$acc end data
+  end subroutine test_allocatable
+end program test
diff --git a/libgomp/testsuite/libgomp.oacc-fortran/optional-data-copyout.f90 b/libgomp/testsuite/libgomp.oacc-fortran/optional-data-copyout.f90
new file mode 100644
index 00000000000..feaa31fa423
--- /dev/null
+++ b/libgomp/testsuite/libgomp.oacc-fortran/optional-data-copyout.f90
@@ -0,0 +1,96 @@
+! Test OpenACC data regions with a copy-out of optional arguments.
+
+! { dg-do run }
+
+program test
+  implicit none
+
+  integer, parameter :: n = 64
+  integer :: i
+  integer :: a_int, b_int, res_int
+  integer :: a_arr(n), b_arr(n), res_arr(n)
+  integer, allocatable :: a_alloc(:), b_alloc(:), res_alloc(:)
+
+  res_int = 0
+
+  call test_int(a_int, b_int)
+  if (res_int .ne. 0) stop 1
+
+  call test_int(a_int, b_int, res_int)
+  if (res_int .ne. a_int * b_int) stop 2
+
+  res_arr(:) = 0
+  do i = 1, n
+    a_arr(i) = i
+    b_arr(i) = n - i + 1
+  end do
+
+  call test_array(a_arr, b_arr)
+  do i = 1, n
+    if (res_arr(i) .ne. 0) stop 3
+  end do
+
+  call test_array(a_arr, b_arr, res_arr)
+  do i = 1, n
+    if (res_arr(i) .ne. a_arr(i) * b_arr(i)) stop 4
+  end do
+
+  allocate (a_alloc(n))
+  allocate (b_alloc(n))
+  allocate (res_alloc(n))
+
+  res_alloc(:) = 0
+  do i = 1, n
+    a_alloc(i) = i
+    b_alloc(i) = n - i + 1
+  end do
+
+  call test_allocatable(a_alloc, b_alloc)
+  do i = 1, n
+    if (res_alloc(i) .ne. 0) stop 5
+  end do
+
+  call test_allocatable(a_alloc, b_alloc, res_alloc)
+  do i = 1, n
+    if (res_alloc(i) .ne. a_alloc(i) * b_alloc(i)) stop 6
+  end do
+
+  deallocate (a_alloc)
+  deallocate (b_alloc)
+  deallocate (res_alloc)
+contains
+  subroutine test_int(a, b, res)
+    integer :: a, b
+    integer, optional :: res
+
+    !$acc data copyin(a, b) copyout(res)
+    !$acc parallel
+    if (present(res)) res = a * b
+    !$acc end parallel
+    !$acc end data
+  end subroutine test_int
+
+  subroutine test_array(a, b, res)
+    integer :: a(n), b(n)
+    integer, optional :: res(n)
+
+    !$acc data copyin(a, b) copyout(res)
+    !$acc parallel loop
+    do i = 1, n
+      if (present(res)) res(i) = a(i) * b(i)
+    end do
+    !$acc end data
+  end subroutine test_array
+
+  subroutine test_allocatable(a, b, res)
+    integer, allocatable :: a(:), b(:)
+    integer, allocatable, optional :: res(:)
+
+    !$acc data copyin(a, b) copyout(res)
+    !$acc parallel loop
+    do i = 1, n
+      if (present(res)) res(i) = a(i) * b(i)
+    end do
+    !$acc end data
+  end subroutine test_allocatable
+end program test
diff --git a/libgomp/testsuite/libgomp.oacc-fortran/optional-data-enter-exit.f90 b/libgomp/testsuite/libgomp.oacc-fortran/optional-data-enter-exit.f90
new file mode 100644
index 00000000000..9ed0f753ea5
--- /dev/null
+++ b/libgomp/testsuite/libgomp.oacc-fortran/optional-data-enter-exit.f90
@@ -0,0 +1,91 @@
+! Test OpenACC unstructured enter data/exit data regions with optional
+! arguments.
+
+! { dg-do run }
+
+program test
+  implicit none
+
+  integer, parameter :: n = 64
+  integer :: a(n), b(n), c(n), res(n)
+  integer :: x, y, z, r, i
+
+  do i = 1, n
+    a(i) = i
+    b(i) = n - i + 1
+    c(i) = i * 3
+  end do
+
+  res = test_array(a)
+  do i = 1, n
+    if (res(i) .ne. a(i)) stop 1
+  end do
+
+  res = test_array(a, b)
+  do i = 1, n
+    if (res(i) .ne. a(i) * b(i)) stop 2
+  end do
+
+  res = test_array(a, b, c)
+  do i = 1, n
+    if (res(i) .ne. a(i) * b(i) + c(i)) stop 3
+  end do
+
+  x = 7
+  y = 3
+  z = 11
+
+  r = test_int(x)
+  if (r .ne. x) stop 4
+
+  r = test_int(x, y)
+  if (r .ne. x * y) stop 5
+
+  r = test_int(x, y, z)
+  if (r .ne. x * y + z) stop 6
+contains
+  function test_array(a, b, c)
+    integer :: a(n)
+    integer, optional :: b(n), c(n)
+    integer :: test_array(n), res(n)
+
+    !$acc enter data copyin(a, b, c) create(res)
+    !$acc parallel loop
+    do i = 1, n
+      res(i) = a(i)
+    end do
+
+    !$acc parallel loop
+    do i = 1, n
+      if (present(b)) then
+        res(i) = res(i) * b(i)
+      end if
+    end do
+
+    !$acc parallel loop
+    do i = 1, n
+      if (present(c)) then
+        res(i) = res(i) + c(i)
+      end if
+    end do
+    !$acc exit data copyout(res) delete(a, b, c)
+
+    test_array = res
+  end function test_array
+
+  function test_int(a, b, c)
+    integer :: a
+    integer, optional :: b, c
+    integer :: test_int, res
+
+    !$acc enter data copyin(a, b, c) create(res)
+    !$acc parallel present(a, b, c, res)
+    res = a
+    if (present(b)) res = res * b
+    if (present(c)) res = res + c
+    !$acc end parallel
+    !$acc exit data copyout(res) delete(a, b, c)
+
+    test_int = res
+  end function test_int
+end program test
diff --git a/libgomp/testsuite/libgomp.oacc-fortran/optional-declare.f90 b/libgomp/testsuite/libgomp.oacc-fortran/optional-declare.f90
new file mode 100644
index 00000000000..074e5a2abb6
--- /dev/null
+++ b/libgomp/testsuite/libgomp.oacc-fortran/optional-declare.f90
@@ -0,0 +1,87 @@
+! Test OpenACC declare directives with optional arguments.
+
+! { dg-do run }
+
+program test
+  implicit none
+
+  integer, parameter :: n = 64
+  integer :: i
+  integer :: a_int, b_int, c_int, res_int
+  integer :: a_arr(n), b_arr(n), c_arr(n), res_arr(n)
+
+  a_int = 7
+  b_int = 3
+  c_int = 11
+
+  call test_int(res_int, a_int)
+  if (res_int .ne. a_int) stop 1
+
+  call test_int(res_int, a_int, b_int)
+  if (res_int .ne. a_int * b_int) stop 2
+
+  call test_int(res_int, a_int, b_int, c_int)
+  if (res_int .ne. a_int * b_int + c_int) stop 3
+
+  do i = 1, n
+    a_arr(i) = i
+    b_arr(i) = n - i + 1
+    c_arr(i) = i * 3
+  end do
+
+  call test_array(res_arr, a_arr)
+  do i = 1, n
+    if (res_arr(i) .ne. a_arr(i)) stop 4
+  end do
+
+  call test_array(res_arr, a_arr, b_arr)
+  do i = 1, n
+    if (res_arr(i) .ne. a_arr(i) * b_arr(i)) stop 5
+  end do
+
+  call test_array(res_arr, a_arr, b_arr, c_arr)
+  do i = 1, n
+    if (res_arr(i) .ne. a_arr(i) * b_arr(i) + c_arr(i)) stop 6
+  end do
+contains
+  subroutine test_int(res, a, b, c)
+    integer :: a
+    integer, optional :: b, c
+    !$acc declare present_or_copyin(a, b, c)
+    integer :: res
+    !$acc declare present_or_copyout(res)
+
+    !$acc parallel
+    res = a
+    if (present(b)) res = res * b
+    if (present(c)) res = res + c
+    !$acc end parallel
+  end subroutine test_int
+
+  subroutine test_array(res, a, b, c)
+    integer :: a(n)
+    integer, optional :: b(n), c(n)
+    !$acc declare present_or_copyin(a, b, c)
+    integer :: res(n)
+    !$acc declare present_or_copyout(res)
+
+    !$acc parallel loop
+    do i = 1, n
+      res(i) = a(i)
+    end do
+
+    !$acc parallel loop
+    do i = 1, n
+      if (present(b)) then
+        res(i) = res(i) * b(i)
+      end if
+    end do
+
+    !$acc parallel loop
+    do i = 1, n
+      if (present(c)) then
+        res(i) = res(i) + c(i)
+      end if
+    end do
+  end subroutine test_array
+end program test
diff --git a/libgomp/testsuite/libgomp.oacc-fortran/optional-firstprivate.f90 b/libgomp/testsuite/libgomp.oacc-fortran/optional-firstprivate.f90
new file mode 100644
index 00000000000..693e6118489
--- /dev/null
+++ b/libgomp/testsuite/libgomp.oacc-fortran/optional-firstprivate.f90
@@ -0,0 +1,112 @@
+! Test that optional arguments work in firstprivate clauses.  The effect of
+! non-present arguments in firstprivate clauses is undefined, and is not
+! tested for.
+
+! { dg-do run }
+
+program test_firstprivate
+  implicit none
+  integer, parameter :: n = 64
+
+  integer :: i, j
+  integer :: a_int, b_int, c_int, res_int
+  integer :: a_arr(n), b_arr(n), c_arr(n), res_arr(n)
+  integer, allocatable :: a_alloc(:), b_alloc(:), c_alloc(:), res_alloc(:)
+
+  a_int = 14
+  b_int = 5
+  c_int = 12
+
+  call test_int(res_int, a_int, b_int, c_int)
+  if (res_int .ne. a_int * b_int + c_int) stop 1
+
+  do i = 1, n
+    a_arr(i) = i
+    b_arr(i) = n - i + 1
+    c_arr(i) = i * 3
+  end do
+
+  call test_array(res_arr, a_arr, b_arr, c_arr)
+  do i = 1, n
+    if (res_arr(i) .ne. a_arr(i) * b_arr(i) + c_arr(i)) stop 2
+  end do
+
+  allocate(a_alloc(n))
+  allocate(b_alloc(n))
+  allocate(c_alloc(n))
+  allocate(res_alloc(n))
+
+  do i = 1, n
+    a_arr(i) = i
+    b_arr(i) = n - i + 1
+    c_arr(i) = i * 3
+  end do
+
+  call test_allocatable(res_alloc, a_alloc, b_alloc, c_alloc)
+  do i = 1, n
+    if (res_alloc(i) .ne. a_alloc(i) * b_alloc(i) + c_alloc(i)) stop 2
+  end do
+
+  deallocate(a_alloc)
+  deallocate(b_alloc)
+  deallocate(c_alloc)
+  deallocate(res_alloc)
+contains
+  subroutine test_int(res, a, b, c)
+    integer :: a
+    integer, optional :: b, c
+    integer :: res
+
+    !$acc parallel firstprivate(a, b, c) copyout(res)
+    res = a
+    if (present(b)) res = res * b
+    if (present(c)) res = res + c
+    !$acc end parallel
+  end subroutine test_int
+
+  subroutine test_array(res, a, b, c)
+    integer :: a(n)
+    integer, optional :: b(n), c(n)
+    integer :: res(n)
+
+    !$acc data copyin(a, b, c) copyout(res)
+    !$acc parallel loop firstprivate(a)
+    do i = 1, n
+      res(i) = a(i)
+    end do
+
+    !$acc parallel loop firstprivate(b)
+    do i = 1, n
+      if (present(b)) res(i) = res(i) * b(i)
+    end do
+
+    !$acc parallel loop firstprivate(c)
+    do i = 1, n
+      if (present(c)) res(i) = res(i) + c(i)
+    end do
+    !$acc end data
+  end subroutine test_array
+
+  subroutine test_allocatable(res, a, b, c)
+    integer, allocatable :: a(:)
+    integer, allocatable, optional :: b(:), c(:)
+    integer, allocatable :: res(:)
+
+    !$acc data copyin(a, b, c) copyout(res)
+    !$acc parallel loop firstprivate(a)
+    do i = 1, n
+      res(i) = a(i)
+    end do
+
+    !$acc parallel loop firstprivate(b)
+    do i = 1, n
+      if (present(b)) res(i) = res(i) * b(i)
+    end do
+
+    !$acc parallel loop firstprivate(c)
+    do i = 1, n
+      if (present(c)) res(i) = res(i) + c(i)
+    end do
+    !$acc end data
+  end subroutine test_allocatable
+end program test_firstprivate
diff --git a/libgomp/testsuite/libgomp.oacc-fortran/optional-host_data.f90 b/libgomp/testsuite/libgomp.oacc-fortran/optional-host_data.f90
new file mode 100644
index 00000000000..a6e41e28b0b
--- /dev/null
+++ b/libgomp/testsuite/libgomp.oacc-fortran/optional-host_data.f90
@@ -0,0 +1,39 @@
+! Test the host_data construct with optional arguments.
+! Based on host_data-1.f90.
+
+! { dg-do run }
+! { dg-additional-options "-cpp" }
+
+program test
+  implicit none
+
+  integer, target :: i
+  integer, pointer :: ip, iph
+
+  ! Assign the same targets
+  ip => i
+  iph => i
+
+  call foo(iph)
+  call foo(iph, ip)
+contains
+  subroutine foo(iph, ip)
+    integer, pointer :: iph
+    integer, pointer, optional :: ip
+
+    !$acc data copyin(i)
+    !$acc host_data use_device(ip)
+
+    ! Test how the pointers compare inside a host_data construct
+    if (present(ip)) then
+#if ACC_MEM_SHARED
+      if (.not. associated(ip, iph)) STOP 1
+#else
+      if (associated(ip, iph)) STOP 2
+#endif
+    end if
+
+    !$acc end host_data
+    !$acc end data
+  end subroutine foo
+end program test
diff --git a/libgomp/testsuite/libgomp.oacc-fortran/optional-nested-calls.f90 b/libgomp/testsuite/libgomp.oacc-fortran/optional-nested-calls.f90
new file mode 100644
index 00000000000..279139f7c59
--- /dev/null
+++ b/libgomp/testsuite/libgomp.oacc-fortran/optional-nested-calls.f90
@@ -0,0 +1,135 @@
+! Test propagation of optional arguments from within an OpenACC parallel region.
+
+! { dg-do run }
+
+program test
+  implicit none
+
+  integer, parameter :: n = 64
+  integer :: i
+  integer :: res_int
+  integer :: a_arr(n), b_arr(n), res_arr(n)
+  integer, allocatable :: a_alloc(:), b_alloc(:), res_alloc(:)
+
+  call test_int_caller(res_int, 5)
+  if (res_int .ne. 10) stop 1
+
+  call test_int_caller(res_int, 2, 3)
+  if (res_int .ne. 11) stop 2
+
+  do i = 1, n
+    a_arr(i) = i
+    b_arr(i) = n - i + 1
+  end do
+
+  call test_array_caller(res_arr, a_arr)
+  do i = 1, n
+    if (res_arr(i) .ne. 2 * a_arr(i)) stop 3
+  end do
+
+  call test_array_caller(res_arr, a_arr, b_arr)
+  do i = 1, n
+    if (res_arr(i) .ne. a_arr(i) * b_arr(i) + a_arr(i) + b_arr(i)) stop 4
+  end do
+
+  allocate(a_alloc(n))
+  allocate(b_alloc(n))
+  allocate(res_alloc(n))
+
+  do i = 1, n
+    a_alloc(i) = i
+    b_alloc(i) = n - i + 1
+  end do
+
+  call test_array_caller(res_arr, a_arr)
+  do i = 1, n
+    if (res_arr(i) .ne. 2 * a_alloc(i)) stop 5
+  end do
+
+  call test_array_caller(res_arr, a_arr, b_arr)
+  do i = 1, n
+    if (res_arr(i) .ne. a_arr(i) * b_alloc(i) + a_alloc(i) + b_alloc(i)) stop 6
+  end do
+
+  deallocate(a_alloc)
+  deallocate(b_alloc)
+  deallocate(res_alloc)
+contains
+  subroutine test_int_caller(res, a, b)
+    integer :: res, a
+    integer, optional :: b
+
+    !$acc data copyin(a, b) copyout (res)
+    !$acc parallel
+    res = a
+    if (present(b)) res = res * b
+    call test_int_callee(res, a, b)
+    !$acc end parallel
+    !$acc end data
+  end subroutine test_int_caller
+
+  subroutine test_int_callee(res, a, b)
+    !$acc routine seq
+    integer :: res, a
+    integer, optional :: b
+
+    res = res + a
+    if (present(b)) res = res + b
+  end subroutine test_int_callee
+
+  subroutine test_array_caller(res, a, b)
+    integer :: res(n), a(n), i
+    integer, optional :: b(n)
+
+    !$acc data copyin(a, b) copyout(res)
+    !$acc parallel
+    !$acc loop seq
+    do i = 1, n
+      res(i) = a(i)
+      if (present(b)) res(i) = res(i) * b(i)
+    end do
+    call test_array_callee(res, a, b)
+    !$acc end parallel
+    !$acc end data
+  end subroutine test_array_caller
+
+  subroutine test_array_callee(res, a, b)
+    !$acc routine seq
+    integer :: res(n), a(n), i
+    integer, optional :: b(n)
+
+    do i = 1, n
+      res(i) = res(i) + a(i)
+      if (present(b)) res(i) = res(i) + b(i)
+    end do
+  end subroutine test_array_callee
+
+  subroutine test_allocatable_caller(res, a, b)
+    integer :: i
+    integer, allocatable :: res(:), a(:)
+    integer, allocatable, optional :: b(:)
+
+    !$acc data copyin(a, b) copyout(res)
+    !$acc parallel
+    !$acc loop seq
+    do i = 1, n
+      res(i) = a(i)
+      if (present(b)) res(i) = res(i) * b(i)
+    end do
+    call test_array_callee(res, a, b)
+    !$acc end parallel
+    !$acc end data
+  end subroutine test_allocatable_caller
+
+  subroutine test_allocatable_callee(res, a, b)
+    !$acc routine seq
+    integer :: i
+    integer, allocatable :: res(:), a(:)
+    integer, allocatable, optional :: b(:)
+
+    do i = 1, n
+      res(i) = res(i) + a(i)
+      if (present(b)) res(i) = res(i) + b(i)
+    end do
+  end subroutine test_allocatable_callee
+end program test
diff --git a/libgomp/testsuite/libgomp.oacc-fortran/optional-private.f90 b/libgomp/testsuite/libgomp.oacc-fortran/optional-private.f90
new file mode 100644
index 00000000000..0320bbb3bc9
--- /dev/null
+++ b/libgomp/testsuite/libgomp.oacc-fortran/optional-private.f90
@@ -0,0 +1,115 @@
+! Test that optional arguments work in private clauses.  The effect of
+! non-present arguments in private clauses is undefined, and is not tested
+! for.  The tests are based on those in private-variables.f90.
+
+! { dg-do run }
+
+program main
+  implicit none
+
+  type vec3
+     integer x, y, z, attr(13)
+  end type vec3
+  integer :: x
+  type(vec3) :: pt
+  integer :: arr(2)
+
+  call t1(x)
+  call t2(pt)
+  call t3(arr)
+contains
+
+  ! Test of gang-private variables declared on loop directive.
+
+  subroutine t1(x)
+    integer, optional :: x
+    integer :: i, arr(32)
+
+    do i = 1, 32
+       arr(i) = i
+    end do
+
+    !$acc parallel copy(arr) num_gangs(32) num_workers(8) vector_length(32)
+    !$acc loop gang private(x)
+    do i = 1, 32
+       x = i * 2;
+       arr(i) = arr(i) + x
+    end do
+    !$acc end parallel
+
+    do i = 1, 32
+       if (arr(i) .ne. i * 3) STOP 1
+    end do
+  end subroutine t1
+
+
+  ! Test of gang-private addressable variable declared on loop directive, with
+  ! broadcasting to partitioned workers.
+
+  subroutine t2(pt)
+    integer i, j, arr(0:32*32)
+    type(vec3), optional :: pt
+
+    do i = 0, 32*32-1
+       arr(i) = i
+    end do
+
+    !$acc parallel copy(arr) num_gangs(32) num_workers(8) vector_length(32)
+    !$acc loop gang private(pt)
+    do i = 0, 31
+       pt%x = i
+       pt%y = i * 2
+       pt%z = i * 4
+       pt%attr(5) = i * 6
+
+       !$acc loop vector
+       do j = 0, 31
+          arr(i * 32 + j) = arr(i * 32 + j) + pt%x + pt%y + pt%z + pt%attr(5);
+       end do
+    end do
+    !$acc end parallel
+
+    do i = 0, 32 * 32 - 1
+       if (arr(i) .ne. i + (i / 32) * 13) STOP 2
+    end do
+  end subroutine t2
+
+  ! Test of vector-private variables declared on loop directive. Array type.
+
+  subroutine t3(pt)
+    integer, optional :: pt(2)
+    integer :: i, j, k, idx, arr(0:32*32*32)
+
+    do i = 0, 32*32*32-1
+       arr(i) = i
+    end do
+
+    !$acc parallel copy(arr) num_gangs(32) num_workers(8) vector_length(32)
+    !$acc loop gang
+    do i = 0, 31
+       !$acc loop worker
+       do j = 0, 31
+          !$acc loop vector private(pt)
+          do k = 0, 31
+             pt(1) = ieor(i, j * 3)
+             pt(2) = ior(i, j * 5)
+             arr(i * 1024 + j * 32 + k) = arr(i * 1024 + j * 32 + k) + pt(1) * k
+             arr(i * 1024 + j * 32 + k) = arr(i * 1024 + j * 32 + k) + pt(2) * k
+          end do
+       end do
+    end do
+    !$acc end parallel
+
+    do i = 0, 32 - 1
+       do j = 0, 32 -1
+          do k = 0, 32 - 1
+             idx = i * 1024 + j * 32 + k
+             if (arr(idx) .ne. idx + ieor(i, j * 3) * k + ior(i, j * 5) * k) then
+                STOP 3
+             end if
+          end do
+       end do
+    end do
+  end subroutine t3
+
+end program main
diff --git a/libgomp/testsuite/libgomp.oacc-fortran/optional-reduction.f90 b/libgomp/testsuite/libgomp.oacc-fortran/optional-reduction.f90
new file mode 100644
index 00000000000..b76db3ef6d3
--- /dev/null
+++ b/libgomp/testsuite/libgomp.oacc-fortran/optional-reduction.f90
@@ -0,0 +1,69 @@
+! Test optional arguments in reduction clauses.  The effect of
+! non-present arguments in reduction clauses is undefined, and is not tested
+! for.  The tests are based on those in reduction-1.f90.
+
+! { dg-do run }
+! { dg-additional-options "-w" }
+
+program optional_reduction
+  implicit none
+
+  integer :: rg, rw, rv, rc
+
+  rg = 0
+  rw = 0
+  rv = 0
+  rc = 0
+
+  call do_test(rg, rw, rv, rc)
+contains
+  subroutine do_test(rg, rw, rv, rc)
+    integer, parameter     :: n = 10, ng = 8, nw = 4, vl = 32
+    integer, optional      :: rg, rw, rv, rc
+    integer                :: i, vresult
+    integer, dimension (n) :: array
+
+    vresult = 0
+    do i = 1, n
+       array(i) = i
+    end do
+
+    !$acc parallel num_gangs(ng) copy(rg)
+    !$acc loop reduction(+:rg) gang
+    do i = 1, n
+       rg = rg + array(i)
+    end do
+    !$acc end parallel
+
+    !$acc parallel num_workers(nw) copy(rw)
+    !$acc loop reduction(+:rw) worker
+    do i = 1, n
+       rw = rw + array(i)
+    end do
+    !$acc end parallel
+
+    !$acc parallel vector_length(vl) copy(rv)
+    !$acc loop reduction(+:rv) vector
+    do i = 1, n
+       rv = rv + array(i)
+    end do
+    !$acc end parallel
+
+    !$acc parallel num_gangs(ng) num_workers(nw) vector_length(vl) copy(rc)
+    !$acc loop reduction(+:rc) gang worker vector
+    do i = 1, n
+       rc = rc + array(i)
+    end do
+    !$acc end parallel
+
+    ! Verify the results
+    do i = 1, n
+       vresult = vresult + array(i)
+    end do
+
+    if (rg .ne. vresult) STOP 1
+    if (rw .ne. vresult) STOP 2
+    if (rv .ne. vresult) STOP 3
+    if (rc .ne. vresult) STOP 4
+  end subroutine do_test
+end program optional_reduction
diff --git a/libgomp/testsuite/libgomp.oacc-fortran/optional-update-device.f90 b/libgomp/testsuite/libgomp.oacc-fortran/optional-update-device.f90
new file mode 100644
index 00000000000..57f69001d3d
--- /dev/null
+++ b/libgomp/testsuite/libgomp.oacc-fortran/optional-update-device.f90
@@ -0,0 +1,121 @@
+! Test OpenACC update to device with an optional argument.
+
+! { dg-do run }
+
+program optional_update_device
+  implicit none
+
+  integer, parameter :: n = 64
+  integer :: i
+  integer :: a_int, b_int, res_int
+  integer :: a_arr(n), b_arr(n), res_arr(n)
+  integer, allocatable :: a_alloc(:), b_alloc(:), res_alloc(:)
+
+  a_int = 5
+  b_int = 11
+
+  call test_int(res_int, a_int)
+  if (res_int .ne. a_int) stop 1
+
+  call test_int(res_int, a_int, b_int)
+  if (res_int .ne. a_int * b_int) stop 2
+
+  res_arr(:) = 0
+  do i = 1, n
+    a_arr(i) = i
+    b_arr(i) = n - i + 1
+  end do
+
+  call test_array(res_arr, a_arr)
+  do i = 1, n
+    if (res_arr(i) .ne. a_arr(i)) stop 3
+  end do
+
+  call test_array(res_arr, a_arr, b_arr)
+  do i = 1, n
+    if (res_arr(i) .ne. a_arr(i) * b_arr(i)) stop 4
+  end do
+
+  allocate (a_alloc(n))
+  allocate (b_alloc(n))
+  allocate (res_alloc(n))
+
+  res_alloc(:) = 0
+  do i = 1, n
+    a_alloc(i) = i
+    b_alloc(i) = n - i + 1
+  end do
+
+  call test_allocatable(res_alloc, a_alloc)
+  do i = 1, n
+    if (res_alloc(i) .ne. a_alloc(i)) stop 5
+  end do
+
+  call test_allocatable(res_alloc, a_alloc, b_alloc)
+  do i = 1, n
+    if (res_alloc(i) .ne. a_alloc(i) * b_alloc(i)) stop 6
+  end do
+
+  deallocate (a_alloc)
+  deallocate (b_alloc)
+  deallocate (res_alloc)
+contains
+  subroutine test_int(res, a, b)
+    integer :: res
+    integer :: a
+    integer, optional :: b
+
+    !$acc data create(a, b, res)
+    !$acc update device(a, b)
+    !$acc parallel
+    res = a
+    if (present(b)) res = res * b
+    !$acc end parallel
+    !$acc update self(res)
+    !$acc end data
+  end subroutine test_int
+
+  subroutine test_array(res, a, b)
+    integer :: res(n)
+    integer :: a(n)
+    integer, optional :: b(n)
+
+    !$acc data create(a, b, res)
+    !$acc update device(a, b)
+    !$acc parallel loop
+    do i = 1, n
+      res(i) = a(i)
+    end do
+
+    !$acc parallel loop
+    do i = 1, n
+      if (present(b)) then
+        res(i) = res(i) * b(i)
+      end if
+    end do
+    !$acc update self(res)
+    !$acc end data
+  end subroutine test_array
+
+  subroutine test_allocatable(res, a, b)
+    integer, allocatable :: res(:)
+    integer, allocatable :: a(:)
+    integer, allocatable, optional :: b(:)
+
+    !$acc data create(a, b, res)
+    !$acc update device(a, b)
+    !$acc parallel loop
+    do i = 1, n
+      res(i) = a(i)
+    end do
+
+    !$acc parallel loop
+    do i = 1, n
+      if (present(b)) then
+        res(i) = res(i) * b(i)
+      end if
+    end do
+    !$acc update self(res)
+    !$acc end data
+  end subroutine test_allocatable
+end program optional_update_device
diff --git a/libgomp/testsuite/libgomp.oacc-fortran/optional-update-host.f90 b/libgomp/testsuite/libgomp.oacc-fortran/optional-update-host.f90
new file mode 100644
index 00000000000..36b94241b11
--- /dev/null
+++ b/libgomp/testsuite/libgomp.oacc-fortran/optional-update-host.f90
@@ -0,0 +1,115 @@
+! Test OpenACC update to host with an optional argument.
+
+! { dg-do run }
+
+program optional_update_host
+  implicit none
+
+  integer, parameter :: n = 64
+  integer :: i
+  integer :: a_int, b_int, res_int
+  integer :: a_arr(n), b_arr(n), res_arr(n)
+  integer, allocatable :: a_alloc(:), b_alloc(:), res_alloc(:)
+
+  a_int = 5
+  b_int = 11
+  res_int = 0
+
+  call test_int(a_int, b_int)
+  if (res_int .ne. 0) stop 1
+
+  call test_int(a_int, b_int, res_int)
+  if (res_int .ne. a_int * b_int) stop 2
+
+  res_arr(:) = 0
+  do i = 1, n
+    a_arr(i) = i
+    b_arr(i) = n - i + 1
+  end do
+
+  call test_array(a_arr, b_arr)
+  do i = 1, n
+    if (res_arr(i) .ne. 0) stop 1
+  end do
+
+  call test_array(a_arr, b_arr, res_arr)
+  do i = 1, n
+    if (res_arr(i) .ne. a_arr(i) * b_arr(i)) stop 2
+  end do
+
+  allocate(a_alloc(n))
+  allocate(b_alloc(n))
+  allocate(res_alloc(n))
+
+  res_alloc(:) = 0
+  do i = 1, n
+    a_alloc(i) = i
+    b_alloc(i) = n - i + 1
+  end do
+
+  call test_allocatable(a_alloc, b_alloc)
+  do i = 1, n
+    if (res_alloc(i) .ne. 0) stop 1
+  end do
+
+  call test_allocatable(a_alloc, b_alloc, res_alloc)
+  do i = 1, n
+    if (res_alloc(i) .ne. a_alloc(i) * b_alloc(i)) stop 2
+  end do
+
+  deallocate(a_alloc)
+  deallocate(b_alloc)
+  deallocate(res_alloc)
+contains
+  subroutine test_int(a, b, res)
+    integer :: a, b
+    integer, optional :: res
+
+    !$acc data create(a, b, res)
+    !$acc update device(a, b)
+    !$acc parallel
+    if (present(res)) res = a
+    if (present(res)) res = res * b
+    !$acc end parallel
+    !$acc update self(res)
+    !$acc end data
+  end subroutine test_int
+
+  subroutine test_array(a, b, res)
+    integer :: a(n), b(n)
+    integer, optional :: res(n)
+
+    !$acc data create(a, b, res)
+    !$acc update device(a, b)
+    !$acc parallel loop
+    do i = 1, n
+      if (present(res)) res(i) = a(i)
+    end do
+
+    !$acc parallel loop
+    do i = 1, n
+      if (present(res)) res(i) = res(i) * b(i)
+    end do
+    !$acc update self(res)
+    !$acc end data
+  end subroutine test_array
+
+  subroutine test_allocatable(a, b, res)
+    integer, allocatable :: a(:), b(:)
+    integer, allocatable, optional :: res(:)
+
+    !$acc data create(a, b, res)
+    !$acc update device(a, b)
+    !$acc parallel loop
+    do i = 1, n
+      if (present(res)) res(i) = a(i)
+    end do
+
+    !$acc parallel loop
+    do i = 1, n
+      if (present(res)) res(i) = res(i) * b(i)
+    end do
+    !$acc update self(res)
+    !$acc end data
+  end subroutine test_allocatable
+end program optional_update_host 

^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: [Patch][OpenMP/OpenACC/Fortran] Fix mapping of optional (present|absent) arguments
  2019-11-20 13:11       ` [Patch][OpenMP/OpenACC/Fortran] Fix mapping of optional (present|absent) arguments Tobias Burnus
@ 2019-11-29 12:17         ` Tobias Burnus
  2019-12-05 15:16         ` Jakub Jelinek
  2019-12-07 14:49         ` [Patch][OpenMP/OpenACC/Fortran] Fix mapping of optional (present|absent) arguments Thomas Schwinge
  2 siblings, 0 replies; 65+ messages in thread
From: Tobias Burnus @ 2019-11-29 12:17 UTC (permalink / raw)
  To: gcc-patches, fortran, Jakub Jelinek, Thomas Schwinge

Early *PING*.

Tobias Burnus wrote:
> This patch does two things regarding explicit and automatical variable 
> mapping to offloaded devices:
>
> * Fixes bugs with optional arguments, which are present. They were 
> mapped but the mapping had issues causing run-time failures.
> * It now also handles absent optional arguments.
>
> Compared to the previous patch set,** I added several OpenMP test 
> cases – and fixed the fallout.
>
> Except for trivial changes to libgomp/oacc-mem.c and omp-low.c, all 
> changes are in fortran/trans-openmp.c and only affect optional arguments.
>
> The patch was bootstrapped and tested on x86_64-gnu-linux w/o 
> offloading-support configured and with nvptx offloading.
>
> Tobias
>
> ** Included in the attached patch are the following previously posted 
> patches: [1] the trivial libgomp/oacc-mem.c change, [2] only the 
> remaining single-line change in omp-low.c, [3] the trans-openmp.c 
> changes (which had to be modified+extended), and [5] the test cases. 
> ([2] and [4] are already in GCC 10.) See: 
> https://gcc.gnu.org/ml/gcc-patches/2019-07/threads.html#00960 for the 
> original patches.
>
> PS: For full OpenMP support, (absent) optional arguments also needed 
> to be handled for data-share clauses.
>

^ permalink raw reply	[flat|nested] 65+ messages in thread

* [PR92726] OpenACC: 'NULL'-in -> no-op, and/or 'NULL'-out (was: [PATCH 1/5, OpenACC] Allow NULL as an argument to OpenACC 2.6 directives)
  2019-07-12 11:36   ` [PATCH 1/5, OpenACC] Allow NULL as an argument to OpenACC 2.6 directives Kwok Cheung Yeung
@ 2019-11-29 14:42     ` Thomas Schwinge
  2019-11-20 13:11       ` [Patch][OpenMP/OpenACC/Fortran] Fix mapping of optional (present|absent) arguments Tobias Burnus
  2019-12-02 16:59       ` [PR92726] OpenACC: 'NULL'-in -> no-op, and/or 'NULL'-out Tobias Burnus
  0 siblings, 2 replies; 65+ messages in thread
From: Thomas Schwinge @ 2019-11-29 14:42 UTC (permalink / raw)
  To: Tobias Burnus; +Cc: Kwok Cheung Yeung, gcc-patches, fortran, jakub

[-- Attachment #1: Type: text/plain, Size: 7352 bytes --]

Hi Tobias!

Reviewing your
<http://mid.mail-archive.com/8be82276-81b1-817c-fcd2-51f24f5fe2d2@codesourcery.com>
"[Patch][OpenMP/OpenACC/Fortran] Fix mapping of optional (present|absent)
arguments" reminded me that still this behavioral change has not been
split out, cited below, that you described as "trivial".

I've just filed <https://gcc.gnu.org/PR92726> "OpenACC: 'NULL'-in ->
no-op, and/or 'NULL'-out", so please reference that one in the ChangeLog
updates.

So, eventually that'll be more than just
'libgomp/oacc-mem.c:update_dev_host', but I understand we need that one
now, for Fortran optional arguments support.  Any other changes can then
be handled later (once the OpenACC specification changes have been
completed).

Please also add a new test case 'libgomp.oacc-c-c++-common/null-1.c' with
a "Test 'NULL'-in -> no-op, and/or 'NULL'-out" header, executing things
like 'acc_update_device (NULL, [...])' etc. for everything that calls
'update_dev_host': 'acc_update_device', 'acc_update_device_async',
'acc_update_self', 'acc_update_self_async'.  These functions are also
called for OpenACC 'update' directives
('libgomp/oacc-parallel.c:GOACC_update'), but I suppose it's not possible
to construct an OpenACC 'update' directive conveying a 'NULL' pointer,
that is, something that would result in 'hostaddrs[i] == NULL'?  Likewise
for Fortran, I suppose.

In 'libgomp/libgomp.texi' then add a note to 'acc_update_device' (and
other relevant functions) like this:

    @@ -2586,6 +2586,9 @@ This function updates the device copy from the previously mapped host memory.
     The host memory is specified with the host address @var{a} and a length of
     @var{len} bytes.
    
    +If @var{a} is the @code{NULL} pointer, this is a no-op.
    +
     [...]


As for 'libgomp/oacc-mem.c:gomp_acc_insert_pointer', that's only called
for OpenACC 'enter data' directives
('libgomp/oacc-parallel.c:GOACC_enter_exit_data'), and specifically only
for 'GOMP_MAP_POINTER', 'GOMP_MAP_TO_PSET'.  Is there a way to construct
a test case that will result in a 'NULL' pointer there, other than via
Fortran optional arguments?  If not, then that hunk should be removed
here, and move into/stay in the Fortran optional arguments patch that
you've posted.

(And that said, Julian's got a patch pending review that gets rid of
'gomp_acc_insert_pointer' and other such black magic, yay.)


Grüße
 Thomas


On 2019-07-12T12:35:05+0100, Kwok Cheung Yeung <kcy@codesourcery.com> wrote:
> Fortran pass-by-reference optional arguments behave much like normal 
> Fortran arguments when lowered to GENERIC/GIMPLE, except they can be 
> null (representing a non-present argument).
>
> Some parts of libgomp (those dealing with updating mappings) currently 
> do not expect to take a null address and fail. These need to be changed 
> to deal with the null appropriately, by turning the operation into a 
> no-op (as you never need to update a non-present argument).
>
> 	libgomp/
> 	* oacc-mem.c (update_dev_host): Return early if the host address
> 	is NULL.
> 	(gomp_acc_insert_pointer): Likewise.
> 	* testsuite/libgomp.oacc-c-c++-common/lib-43.c: Remove.
> 	* testsuite/libgomp.oacc-c-c++-common/lib-47.c: Likewise.
> ---
>   libgomp/oacc-mem.c                                 |  9 ++++
>   .../testsuite/libgomp.oacc-c-c++-common/lib-43.c   | 51 ----------------------
>   .../testsuite/libgomp.oacc-c-c++-common/lib-47.c   | 49 ---------------------
>   3 files changed, 9 insertions(+), 100 deletions(-)
>   delete mode 100644 libgomp/testsuite/libgomp.oacc-c-c++-common/lib-43.c
>   delete mode 100644 libgomp/testsuite/libgomp.oacc-c-c++-common/lib-47.c
>
> diff --git a/libgomp/oacc-mem.c b/libgomp/oacc-mem.c
> index 2f27100..8cc5120 100644
> --- a/libgomp/oacc-mem.c
> +++ b/libgomp/oacc-mem.c
> @@ -831,6 +831,12 @@ update_dev_host (int is_dev, void *h, size_t s, int async)
>     if (acc_dev->capabilities & GOMP_OFFLOAD_CAP_SHARED_MEM)
>       return;
>
> +  /* Fortran optional arguments that are non-present result in a
> +     null host address here.  This can safely be ignored as it is
> +     not possible to 'update' a non-present optional argument.  */
> +  if (h == NULL)
> +    return;
> +
>     acc_prof_info prof_info;
>     acc_api_info api_info;
>     bool profiling_p = GOACC_PROFILING_SETUP_P (thr, &prof_info, &api_info);
> @@ -901,6 +907,9 @@ gomp_acc_insert_pointer (size_t mapnum, void **hostaddrs, size_t *sizes,
>     struct goacc_thread *thr = goacc_thread ();
>     struct gomp_device_descr *acc_dev = thr->dev;
>
> +  if (*hostaddrs == NULL)
> +    return;
> +
>     if (acc_is_present (*hostaddrs, *sizes))
>       {
>         splay_tree_key n;
> diff --git a/libgomp/testsuite/libgomp.oacc-c-c++-common/lib-43.c b/libgomp/testsuite/libgomp.oacc-c-c++-common/lib-43.c
> deleted file mode 100644
> index 5db2912..0000000
> --- a/libgomp/testsuite/libgomp.oacc-c-c++-common/lib-43.c
> +++ /dev/null
> @@ -1,51 +0,0 @@
> -/* Exercise acc_update_device with a NULL data address on nvidia targets.  */
> -
> -/* { dg-do run { target openacc_nvidia_accel_selected } } */
> -
> -#include <stdio.h>
> -#include <stdlib.h>
> -#include <openacc.h>
> -
> -int
> -main (int argc, char **argv)
> -{
> -  const int N = 256;
> -  int i;
> -  unsigned char *h;
> -  void *d;
> -
> -  h = (unsigned char *) malloc (N);
> -
> -  for (i = 0; i < N; i++)
> -    {
> -      h[i] = i;
> -    }
> -
> -  d = acc_copyin (h, N);
> -  if (!d)
> -    abort ();
> -
> -  for (i = 0; i < N; i++)
> -    {
> -      h[i] = 0xab;
> -    }
> -
> -  fprintf (stderr, "CheCKpOInT\n");
> -  acc_update_device (0, N);
> -
> -  acc_copyout (h, N);
> -
> -  for (i = 0; i < N; i++)
> -    {
> -      if (h[i] != 0xab)
> -	abort ();
> -    }
> -
> -  free (h);
> -
> -  return 0;
> -}
> -
> -/* { dg-output "CheCKpOInT(\n|\r\n|\r).*" } */
> -/* { dg-output "\\\[\[^\n\r]*,256\\\] is not mapped" } */
> -/* { dg-shouldfail "" } */
> diff --git a/libgomp/testsuite/libgomp.oacc-c-c++-common/lib-47.c b/libgomp/testsuite/libgomp.oacc-c-c++-common/lib-47.c
> deleted file mode 100644
> index c214042..0000000
> --- a/libgomp/testsuite/libgomp.oacc-c-c++-common/lib-47.c
> +++ /dev/null
> @@ -1,49 +0,0 @@
> -/* Exercise acc_update_self with a NULL data mapping on nvidia targets.  */
> -
> -/* { dg-do run { target openacc_nvidia_accel_selected } } */
> -
> -#include <stdio.h>
> -#include <string.h>
> -#include <stdlib.h>
> -#include <openacc.h>
> -
> -int
> -main (int argc, char **argv)
> -{
> -  const int N = 256;
> -  int i;
> -  unsigned char *h;
> -  void *d;
> -
> -  h = (unsigned char *) malloc (N);
> -
> -  for (i = 0; i < N; i++)
> -    {
> -      h[i] = i;
> -    }
> -
> -  d = acc_copyin (h, N);
> -  if (!d)
> -    abort ();
> -
> -  memset (&h[0], 0, N);
> -
> -  fprintf (stderr, "CheCKpOInT\n");
> -  acc_update_self (0, N);
> -
> -  for (i = 0; i < N; i++)
> -    {
> -      if (h[i] != i)
> -	abort ();
> -    }
> -
> -  acc_delete (h, N);
> -
> -  free (h);
> -
> -  return 0;
> -}
> -
> -/* { dg-output "CheCKpOInT(\n|\r\n|\r).*" } */
> -/* { dg-output "\\\[\[^\n\r]*,256\\\] is not mapped" } */
> -/* { dg-shouldfail "" } */

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 658 bytes --]

^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: [PR92726] OpenACC: 'NULL'-in -> no-op, and/or 'NULL'-out
  2019-11-29 14:42     ` [PR92726] OpenACC: 'NULL'-in -> no-op, and/or 'NULL'-out (was: [PATCH 1/5, OpenACC] Allow NULL as an argument to OpenACC 2.6 directives) Thomas Schwinge
  2019-11-20 13:11       ` [Patch][OpenMP/OpenACC/Fortran] Fix mapping of optional (present|absent) arguments Tobias Burnus
@ 2019-12-02 16:59       ` Tobias Burnus
  1 sibling, 0 replies; 65+ messages in thread
From: Tobias Burnus @ 2019-12-02 16:59 UTC (permalink / raw)
  To: Thomas Schwinge, Tobias Burnus; +Cc: Kwok Cheung Yeung, gcc-patches, fortran

[-- Attachment #1: Type: text/plain, Size: 1662 bytes --]

Hi Thomas,

On 11/29/19 3:40 PM, Thomas Schwinge wrote:
> "[Patch][OpenMP/OpenACC/Fortran] Fix mapping of optional (present|absent)
> arguments" reminded me that still this behavioral change has not been
> split out, cited below, that you described as "trivial".
>
> I've just filed <https://gcc.gnu.org/PR92726> "OpenACC: 'NULL'-in ->
> no-op, and/or 'NULL'-out", so please reference that one in the ChangeLog
> updates.
>
> So, eventually that'll be more than just
> 'libgomp/oacc-mem.c:update_dev_host', but I understand we need that one
> now, for Fortran optional arguments support.  Any other changes can then
> be handled later (once the OpenACC specification changes have been
> completed).

For the changes at hand, they are called as library for 
update_device(_async) and update_self(_async). And via the 'update' 
directives via the 'maps' alway_pointer, (force_)to and (force_)from. 
'insert_pointer' is called via 'GOACC_enter_exit_data for 'enter' if the 
pointer can already be found; hence, I think the latter is untestable.

Side note: the [update_(device|self)]_async variants are mentioned  in 
the libgomp.texi but not really documented; they only appear at the end 
of "OpenACC Profiling Interface" – last block at: 
https://gcc.gnu.org/onlinedocs/libgomp/OpenACC-Profiling-Interface.html

I have the feeling the _async variants should be properly documented in 
the manual; especially, the permitted values for the third argument.

> Please also add a new test case 'libgomp.oacc-c-c++-common/null-1.c' with
> a "Test 'NULL'-in -> no-op, and/or 'NULL'-out" header, executing things […]

How about the attached patch?

Tobias


[-- Attachment #2: acc-null-v2.diff --]
[-- Type: text/x-patch, Size: 7847 bytes --]

2019-12-02  Tobias Burnus  <tobias@codesourcery.com>
	    Kwok Cheung Yeung <kcy@codesourcery.com>

	libgomp/
	* oacc-mem.c (update_dev_host, gomp_acc_insert_pointer): Just return
	if input it a NULL pointer.
	* testsuite/libgomp.oacc-c-c++-common/lib-43.c: Remove; dependent on
	diagnostic of NULL pointer.
	* testsuite/libgomp.oacc-c-c++-common/lib-47.c: Likewise.
	* testsuite/libgomp.oacc-c-c++-common/update-2.c: New; check whether
	NULL is handled with update.
	* testsuite/libgomp.oacc-fortran/update-2.f90: Ditto.


 libgomp/libgomp.texi                                   |  4 ++
 libgomp/oacc-mem.c                                     |  9 ++++
 libgomp/testsuite/libgomp.oacc-c-c++-common/lib-43.c   | 51 ----------------------
 libgomp/testsuite/libgomp.oacc-c-c++-common/lib-47.c   | 49 ---------------------
 libgomp/testsuite/libgomp.oacc-c-c++-common/update-2.c | 33 ++++++++++++++
 libgomp/testsuite/libgomp.oacc-fortran/update-2.f90    | 40 +++++++++++++++++
 6 files changed, 86 insertions(+), 100 deletions(-)

diff --git a/libgomp/libgomp.texi b/libgomp/libgomp.texi
index 6db895f6272..4532e366f4b 100644
--- a/libgomp/libgomp.texi
+++ b/libgomp/libgomp.texi
@@ -2536,6 +2536,8 @@ This function updates the device copy from the previously mapped host memory.
 The host memory is specified with the host address @var{a} and a length of
 @var{len} bytes.
 
+If @var{a} is the @code{NULL} pointer, this is a no-op.
+
 In Fortran, two (2) forms are supported. In the first form, @var{a} specifies
 a contiguous array section. The second form @var{a} specifies a variable or
 array element and @var{len} specifies the length in bytes.
@@ -2569,6 +2571,8 @@ This function updates the host copy from the previously mapped device memory.
 The host memory is specified with the host address @var{a} and a length of
 @var{len} bytes.
 
+If @var{a} is the @code{NULL} pointer, this is a no-op.
+
 In Fortran, two (2) forms are supported. In the first form, @var{a} specifies
 a contiguous array section. The second form @var{a} specifies a variable or
 array element and @var{len} specifies the length in bytes.
diff --git a/libgomp/oacc-mem.c b/libgomp/oacc-mem.c
index aafe88d3a14..55c195bd819 100644
--- a/libgomp/oacc-mem.c
+++ b/libgomp/oacc-mem.c
@@ -829,6 +829,12 @@ update_dev_host (int is_dev, void *h, size_t s, int async)
   if (acc_dev->capabilities & GOMP_OFFLOAD_CAP_SHARED_MEM)
     return;
 
+  /* Fortran optional arguments that are non-present result in a
+     NULL host address here.  This can safely be ignored as it is
+     not possible to 'update' a non-present optional argument.  */
+  if (h == NULL)
+    return;
+
   acc_prof_info prof_info;
   acc_api_info api_info;
   bool profiling_p = GOACC_PROFILING_SETUP_P (thr, &prof_info, &api_info);
@@ -899,6 +905,9 @@ gomp_acc_insert_pointer (size_t mapnum, void **hostaddrs, size_t *sizes,
   struct goacc_thread *thr = goacc_thread ();
   struct gomp_device_descr *acc_dev = thr->dev;
 
+  if (*hostaddrs == NULL)
+    return;
+
   if (acc_is_present (*hostaddrs, *sizes))
     {
       splay_tree_key n;
diff --git a/libgomp/testsuite/libgomp.oacc-c-c++-common/lib-43.c b/libgomp/testsuite/libgomp.oacc-c-c++-common/lib-43.c
deleted file mode 100644
index 5db29124e9e..00000000000
--- a/libgomp/testsuite/libgomp.oacc-c-c++-common/lib-43.c
+++ /dev/null
@@ -1,51 +0,0 @@
-/* Exercise acc_update_device with a NULL data address on nvidia targets.  */
-
-/* { dg-do run { target openacc_nvidia_accel_selected } } */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <openacc.h>
-
-int
-main (int argc, char **argv)
-{
-  const int N = 256;
-  int i;
-  unsigned char *h;
-  void *d;
-
-  h = (unsigned char *) malloc (N);
-
-  for (i = 0; i < N; i++)
-    {
-      h[i] = i;
-    }
-
-  d = acc_copyin (h, N);
-  if (!d)
-    abort ();
-
-  for (i = 0; i < N; i++)
-    {
-      h[i] = 0xab;
-    }
-
-  fprintf (stderr, "CheCKpOInT\n");
-  acc_update_device (0, N);
-
-  acc_copyout (h, N);
-
-  for (i = 0; i < N; i++)
-    {
-      if (h[i] != 0xab)
-	abort ();
-    }
-
-  free (h);
-
-  return 0;
-}
-
-/* { dg-output "CheCKpOInT(\n|\r\n|\r).*" } */
-/* { dg-output "\\\[\[^\n\r]*,256\\\] is not mapped" } */
-/* { dg-shouldfail "" } */
diff --git a/libgomp/testsuite/libgomp.oacc-c-c++-common/lib-47.c b/libgomp/testsuite/libgomp.oacc-c-c++-common/lib-47.c
deleted file mode 100644
index c2140429cb1..00000000000
--- a/libgomp/testsuite/libgomp.oacc-c-c++-common/lib-47.c
+++ /dev/null
@@ -1,49 +0,0 @@
-/* Exercise acc_update_self with a NULL data mapping on nvidia targets.  */
-
-/* { dg-do run { target openacc_nvidia_accel_selected } } */
-
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-#include <openacc.h>
-
-int
-main (int argc, char **argv)
-{
-  const int N = 256;
-  int i;
-  unsigned char *h;
-  void *d;
-
-  h = (unsigned char *) malloc (N);
-
-  for (i = 0; i < N; i++)
-    {
-      h[i] = i;
-    }
-
-  d = acc_copyin (h, N);
-  if (!d)
-    abort ();
-
-  memset (&h[0], 0, N);
-
-  fprintf (stderr, "CheCKpOInT\n");
-  acc_update_self (0, N);
-
-  for (i = 0; i < N; i++)
-    {
-      if (h[i] != i)
-	abort ();
-    }
-
-  acc_delete (h, N);
-
-  free (h);
-
-  return 0;
-}
-
-/* { dg-output "CheCKpOInT(\n|\r\n|\r).*" } */
-/* { dg-output "\\\[\[^\n\r]*,256\\\] is not mapped" } */
-/* { dg-shouldfail "" } */
diff --git a/libgomp/testsuite/libgomp.oacc-c-c++-common/update-2.c b/libgomp/testsuite/libgomp.oacc-c-c++-common/update-2.c
new file mode 100644
index 00000000000..7b6f8500b5e
--- /dev/null
+++ b/libgomp/testsuite/libgomp.oacc-c-c++-common/update-2.c
@@ -0,0 +1,33 @@
+/* Updating NULL pointer shall not fail at run time.
+   Cf. PR libgomp/92726  */
+
+#include <openacc.h>
+
+int
+main ()
+{
+  float *ptr = NULL;
+
+  #pragma acc enter data copyin(ptr)
+  #pragma acc enter data present_or_copyin(ptr)
+  #pragma acc enter data create(ptr)
+  #pragma acc enter data pcreate(ptr)
+
+  #pragma acc update self(ptr)
+  #pragma acc update host(ptr)
+  #pragma acc update device(ptr)
+
+  acc_update_device (ptr, 0);
+  acc_update_device (NULL, 0L);
+
+  acc_update_device_async (ptr, 0, acc_async_sync);
+  acc_update_device_async (NULL, 0L, acc_async_sync);
+
+  acc_update_self (ptr, 0);
+  acc_update_self (NULL, 0L);
+
+  acc_update_self_async (ptr, 0, acc_async_sync);
+  acc_update_self_async (NULL, 0L, acc_async_sync);
+
+  return 0;
+}
diff --git a/libgomp/testsuite/libgomp.oacc-fortran/update-2.f90 b/libgomp/testsuite/libgomp.oacc-fortran/update-2.f90
new file mode 100644
index 00000000000..632ceb9ca7d
--- /dev/null
+++ b/libgomp/testsuite/libgomp.oacc-fortran/update-2.f90
@@ -0,0 +1,40 @@
+! Updating NULL pointer shall not fail at run time
+! Cf. PR libgomp/92726
+!
+
+program main
+  use openacc
+  use iso_c_binding
+  implicit none (type, external)
+
+  real, pointer :: ptr
+  real, pointer :: ptr2(:,:)
+
+  nullify(ptr)
+  nullify(ptr2)
+
+  !$acc enter data copyin(ptr, ptr2)
+  !$acc enter data present_or_copyin(ptr, ptr2)
+  !$acc enter data create(ptr, ptr2)
+  !$acc enter data pcreate(ptr, ptr2)
+
+  !$acc update self(ptr, ptr2)
+  !$acc update host(ptr, ptr2)
+  !$acc update device(ptr, ptr2)
+
+  call acc_update_device (ptr, 0_c_int32_t)
+  call acc_update_device (ptr2, 0_c_int64_t)
+  call acc_update_device (c_null_ptr, 0)
+
+  call acc_update_device_async (ptr, 0_c_int32_t, acc_async_sync)
+  call acc_update_device_async (ptr, 0_c_int64_t, acc_async_sync)
+  call acc_update_device_async (c_null_ptr, 0, acc_async_sync)
+
+  call acc_update_self (ptr, 0_c_int32_t)
+  call acc_update_self (ptr, 0_c_int64_t)
+  call acc_update_self (c_null_ptr, 0)
+
+  call acc_update_self_async (ptr, 0_c_int32_t, acc_async_sync)
+  call acc_update_self_async (ptr, 0_c_int64_t, acc_async_sync)
+  call acc_update_self_async (c_null_ptr, 0, acc_async_sync)
+end program main

^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: [Patch][OpenMP/OpenACC/Fortran] Fix mapping of optional (present|absent) arguments
  2019-11-20 13:11       ` [Patch][OpenMP/OpenACC/Fortran] Fix mapping of optional (present|absent) arguments Tobias Burnus
  2019-11-29 12:17         ` Tobias Burnus
@ 2019-12-05 15:16         ` Jakub Jelinek
  2019-12-05 15:47           ` [RFC] Characters per line: from punch card (80) to line printer (132) (was: [Patch][OpenMP/OpenACC/Fortran] Fix mapping of optional (present|absent) arguments) Thomas Schwinge
  2019-12-07 14:49         ` [Patch][OpenMP/OpenACC/Fortran] Fix mapping of optional (present|absent) arguments Thomas Schwinge
  2 siblings, 1 reply; 65+ messages in thread
From: Jakub Jelinek @ 2019-12-05 15:16 UTC (permalink / raw)
  To: Tobias Burnus; +Cc: gcc-patches, fortran, Thomas Schwinge

On Wed, Nov 20, 2019 at 02:06:18PM +0100, Tobias Burnus wrote:
> ** Included in the attached patch are the following previously posted
> patches: [1] the trivial libgomp/oacc-mem.c change, [2] only the remaining
> single-line change in omp-low.c, [3] the trans-openmp.c changes (which had
> to be modified+extended), and [5] the test cases. ([2] and [4] are already
> in GCC 10.) See:
> https://gcc.gnu.org/ml/gcc-patches/2019-07/threads.html#00960 for the
> original patches.
> 
> PS: For full OpenMP support, (absent) optional arguments also needed to be
> handled for data-share clauses.

Sure.

> 2019-10-20  Tobias Burnus  <tobias@codesourcery.com>
> 	    Kwok Cheung Yeung <kcy@codesourcery.com>
> 
> 	gcc/fortran/
> 	* trans-openmp.c (gfc_build_conditional_assign, 
> 	gfc_build_conditional_assign_expr): New static functions.
> 	(gfc_omp_finish_clause, gfc_trans_omp_clauses): Handle mapping of
> 	absent optional arguments and fix mapping of present optional args.
> 
> 	gcc/
> 	* omp-low.c (lower_omp_target): For optional arguments, deref once
> 	more to obtain the type.
> 
> 	libgomp/
> 	* oacc-mem.c (update_dev_host, gomp_acc_insert_pointer): Just return
> 	if input it a NULL pointer.
> 	* testsuite/libgomp.oacc-c-c++-common/lib-43.c: Remove; dependent on
> 	diagnostic of NULL pointer.
> 	* testsuite/libgomp.oacc-c-c++-common/lib-47.c: Ditto.
> 	* testsuite/libgomp.fortran/optional-map.f90: New.
> 	* testsuite/libgomp.fortran/use_device_addr-1.f90
> 	(test_dummy_opt_callee_1_absent): New.
> 	(test_dummy_opt_call_1): Call it.
> 	* testsuite/libgomp.fortran/use_device_addr-2.f90: Likewise.
> 	* testsuite/libgomp.fortran/use_device_addr-3.f90: Likewise.
> 	* testsuite/libgomp.fortran/use_device_addr-4.f90: Likewise.
> 	* testsuite/libgomp.oacc-fortran/optional-cache.f95: New.
> 	* testsuite/libgomp.oacc-fortran/optional-data-copyin-by-value.f90: New.
> 	* testsuite/libgomp.oacc-fortran/optional-data-copyin.f90: New.
> 	* testsuite/libgomp.oacc-fortran/optional-data-copyout.f90: New.
> 	* testsuite/libgomp.oacc-fortran/optional-data-enter-exit.f90: New.
> 	* testsuite/libgomp.oacc-fortran/optional-declare.f90: New.
> 	* testsuite/libgomp.oacc-fortran/optional-firstprivate.f90: New.
> 	* testsuite/libgomp.oacc-fortran/optional-host_data.f90: New.
> 	* testsuite/libgomp.oacc-fortran/optional-nested-calls.f90: New.
> 	* testsuite/libgomp.oacc-fortran/optional-private.f90: New.
> 	* testsuite/libgomp.oacc-fortran/optional-reduction.f90: New.
> 	* testsuite/libgomp.oacc-fortran/optional-update-device.f90: New.
> 	* testsuite/libgomp.oacc-fortran/optional-update-host.f90: New.

Ok, with some formatting nits fixed.

> @@ -1199,6 +1257,8 @@ gfc_omp_finish_clause (tree c, gimple_seq *pre_p)
>      }
>  
>    tree c2 = NULL_TREE, c3 = NULL_TREE, c4 = NULL_TREE;
> +  tree present = gfc_omp_is_optional_argument (decl)
> +		 ? gfc_omp_check_optional_argument (decl, true) : NULL_TREE;

I think emacs users (I'm not one of them) want ()s around, otherwise emacs
misformats that.  So
  tree present = (gfc_omp_is_optional_argument (decl)
		  ? gfc_omp_check_optional_argument (decl, true) : NULL_TREE);

> @@ -1232,17 +1314,43 @@ gfc_omp_finish_clause (tree c, gimple_seq *pre_p)
>        stmtblock_t block;
>        gfc_start_block (&block);
>        tree type = TREE_TYPE (decl);
> -      tree ptr = gfc_conv_descriptor_data_get (decl);
> +      tree ptr;
> +
> +      if (present)
> +	ptr = gfc_build_conditional_assign_expr (
> +		&block, present,
> +		gfc_conv_descriptor_data_get (decl),
> +		null_pointer_node);

I must say I don't like very much formatting like that, I'd find it cleaner
to use temporary to have shorter argument and put all the arguments after
the ( column.

> +      else
> +	ptr = gfc_conv_descriptor_data_get (decl);

In this case, it could even be:
      ptr = gfc_conv_descriptor_data_get (decl);
      if (present)
	ptr = gfc_build_conditional_assign_expr (&block, present, ptr,
						 null_pointer_node);
by just using the same call from the else.

> @@ -2252,6 +2385,9 @@ gfc_trans_omp_clauses (stmtblock_t *block, gfc_omp_clauses *clauses,
>  		TREE_ADDRESSABLE (decl) = 1;
>  	      if (n->expr == NULL || n->expr->ref->u.ar.type == AR_FULL)
>  		{
> +		  tree present = gfc_omp_is_optional_argument (decl)
> +				 ? gfc_omp_check_optional_argument (decl, true)
> +				 : NULL_TREE;
>  		  if (POINTER_TYPE_P (TREE_TYPE (decl))
>  		      && (gfc_omp_privatize_by_reference (decl)
>  			  || GFC_DECL_GET_SCALAR_POINTER (decl)

See above.

> @@ -2284,6 +2420,10 @@ gfc_trans_omp_clauses (stmtblock_t *block, gfc_omp_clauses *clauses,
>  		    {
>  		      tree type = TREE_TYPE (decl);
>  		      tree ptr = gfc_conv_descriptor_data_get (decl);
> +		      if (present)
> +			ptr = gfc_build_conditional_assign_expr (
> +			       block, present, ptr,
> +			       null_pointer_node);

And here the other comment.  It is much more indented though, but you could
use a temporary, like:
		      tree nullarg = null_pointer_node;
		      if (present)
			ptr
			  = gfc_build_conditional_assign_expr (block, present,
							       ptr, nullarg);
Though, if it is too much for you, ignore.
Another option would be shorten the name of the function, say
s/conditional/cond/.
There were some discussions about lifting the 80 column restriction and bump
it to something like +-130, but nothing happened yet.

> +			  ptr = gfc_build_conditional_assign_expr (
> +				  block, present, ptr,
> +				  null_pointer_node);

Again.

> +			  stmtblock_t cond_block;
> +			  gfc_init_block (&cond_block);
> +			  tree size = gfc_full_array_size (&cond_block, decl,
> +					GFC_TYPE_ARRAY_RANK (type));

Here one could use a temporary for GFC_TYPE_ARRAY_RANK (type);

> +			  if (present)
> +			    {
> +			      tree var = gfc_create_var (gfc_array_index_type,
> +							 NULL);
> +			      tree cond = fold_build2_loc (input_location,
> +							   NE_EXPR,
> +							   boolean_type_node,
> +							   present,
> +							   null_pointer_node);
> +			      gfc_add_modify (&cond_block, var, size);
> +			      gfc_add_expr_to_block (block,
> +				build3_loc (input_location, COND_EXPR,
> +					    void_type_node, cond,
> +					    gfc_finish_block (&cond_block),
> +					    NULL_TREE));

And here for the expr, perhaps just reuse the cond variable.

> @@ -2346,6 +2534,18 @@ gfc_trans_omp_clauses (stmtblock_t *block, gfc_omp_clauses *clauses,
>  					   OMP_CLAUSE_SIZE (node), elemsz);
>  			}
>  		    }
> +		  else if (present
> +			   && TREE_CODE (decl) == INDIRECT_REF
> +			   && TREE_CODE (TREE_OPERAND (decl, 0))
> +				== INDIRECT_REF)

Above I'd expect
			   && (TREE_CODE (TREE_OPERAND (decl, 0))
			       == INDIRECT_REF))
but perhaps I'm just pushing my coding style too much, ignore in that case.

	Jakub

^ permalink raw reply	[flat|nested] 65+ messages in thread

* [RFC] Characters per line: from punch card (80) to line printer (132) (was: [Patch][OpenMP/OpenACC/Fortran] Fix mapping of optional (present|absent) arguments)
  2019-12-05 15:16         ` Jakub Jelinek
@ 2019-12-05 15:47           ` Thomas Schwinge
  2019-12-05 16:04             ` Jakub Jelinek
                               ` (3 more replies)
  0 siblings, 4 replies; 65+ messages in thread
From: Thomas Schwinge @ 2019-12-05 15:47 UTC (permalink / raw)
  To: gcc; +Cc: gcc-patches, fortran, Jakub Jelinek, Tobias Burnus, Michael Meissner

[-- Attachment #1: Type: text/plain, Size: 2111 bytes --]

Hi!

;-P Jakub, thanks for furnishing me a fit occasion here:

On 2019-12-05T16:15:15+0100, Jakub Jelinek <jakub@redhat.com> wrote:
> [...] much more indented though, but you could
> use a temporary, like:
> 		      tree nullarg = null_pointer_node;

I object to cluttering the code by introducing temporary variables/names
just for the sake of a few characters of screen width.  Even if located
close lexically, when reading the following code you still have to trace
back from the 'nullarg' usage to its 'null_pointer_node' definition in
order to figure out what a 'nullarg' might be:

> 		      if (present)
> 			ptr
> 			  = gfc_build_conditional_assign_expr (block, present,
> 							       ptr, nullarg);

> Another option would be shorten the name of the function, say
> s/conditional/cond/.

Likewise I object to "crippling" identifier names like that just for the
sake of a few characters of screen width.  (Here of course, "cond", or
the existing "expr" might be fine abbreviations, but my point is about
the general case.)

> There were some discussions about lifting the 80 column restriction and bump
> it to something like +-130, but nothing happened yet.

Indeed.  :-)

In the relevant session at the GNU Tools Cauldron 2019, Michael Meissner
stated that even he is not using a 80 x 24 terminal anymore, and that
should tell us something.  ;-)

So, I formally propose that we lift this characters per line restriction
from IBM punch card (80) to mainframe line printer (132).

Nonwithstanding that, we should try to not overstrain that; deep
indentation often is a sign that code should be split out into a separate
function, for example.  My point is just to avoid things like the two
examples cited above.

Also, I'm not proposing any mass-reformatting of the existing code, or
re-writing all "expr" into "expression".

Tasks:

  - Discussion.
  - Get agreement/make a decision (by means still to be determined).
  - Put suitable Emacs/Vim configuration files into the source tree?
  - Update coding style guidelines.


Grüße
 Thomas

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 658 bytes --]

^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: [RFC] Characters per line: from punch card (80) to line printer (132) (was: [Patch][OpenMP/OpenACC/Fortran] Fix mapping of optional (present|absent) arguments)
  2019-12-05 15:47           ` [RFC] Characters per line: from punch card (80) to line printer (132) (was: [Patch][OpenMP/OpenACC/Fortran] Fix mapping of optional (present|absent) arguments) Thomas Schwinge
@ 2019-12-05 16:04             ` Jakub Jelinek
  2019-12-05 20:21               ` Segher Boessenkool
  2019-12-05 16:17             ` Joseph Myers
                               ` (2 subsequent siblings)
  3 siblings, 1 reply; 65+ messages in thread
From: Jakub Jelinek @ 2019-12-05 16:04 UTC (permalink / raw)
  To: Thomas Schwinge
  Cc: gcc, gcc-patches, fortran, Tobias Burnus, Michael Meissner

On Thu, Dec 05, 2019 at 04:46:45PM +0100, Thomas Schwinge wrote:
> Hi!
> 
> ;-P Jakub, thanks for furnishing me a fit occasion here:
> 
> On 2019-12-05T16:15:15+0100, Jakub Jelinek <jakub@redhat.com> wrote:
> > [...] much more indented though, but you could
> > use a temporary, like:
> > 		      tree nullarg = null_pointer_node;
> 
> I object to cluttering the code by introducing temporary variables/names
> just for the sake of a few characters of screen width.  Even if located
> close lexically, when reading the following code you still have to trace
> back from the 'nullarg' usage to its 'null_pointer_node' definition in
> order to figure out what a 'nullarg' might be:
> 
> > 		      if (present)
> > 			ptr
> > 			  = gfc_build_conditional_assign_expr (block, present,
> > 							       ptr, nullarg);
> 
> > Another option would be shorten the name of the function, say
> > s/conditional/cond/.
> 
> Likewise I object to "crippling" identifier names like that just for the
> sake of a few characters of screen width.  (Here of course, "cond", or
> the existing "expr" might be fine abbreviations, but my point is about
> the general case.)

The point about temporaries is general, and I believe they actually make
code much more readable.  Mostly about coding style like:
	t = fold_build2_loc (loc, code, fold_build2_loc (loc, code2,
							 something1,
							 something2),
			     fold_build2_loc (loc, code3, something3,
					      something4));
vs.
	tree op1 = fold_build2_loc (loc, code2, something1, something2);
	tree op2 = fold_build2_loc (loc, code3, something3, something4);
	t = fold_build2_loc (loc, code, op1, op2);
The above case is extreme in both being indented quite a lot (general rule
is to consider outlining something into a function then) and using
way too long function names.  If you look at the earlier suggestion where
the code is indented reasonably, using the temporary there makes the code more
readable and shorter.

> 
> > There were some discussions about lifting the 80 column restriction and bump
> > it to something like +-130, but nothing happened yet.
> 
> Indeed.  :-)
> 
> In the relevant session at the GNU Tools Cauldron 2019, Michael Meissner
> stated that even he is not using a 80 x 24 terminal anymore, and that
> should tell us something.  ;-)
> 
> So, I formally propose that we lift this characters per line restriction
> from IBM punch card (80) to mainframe line printer (132).

Such a proposal would need to be accompanied with a wwwdocs
codingconventions.html patch and contrib/check_GNU_style.{sh,py} patch I
guess ;)

	Jakub

^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: [RFC] Characters per line: from punch card (80) to line printer (132) (was: [Patch][OpenMP/OpenACC/Fortran] Fix mapping of optional (present|absent) arguments)
  2019-12-05 15:47           ` [RFC] Characters per line: from punch card (80) to line printer (132) (was: [Patch][OpenMP/OpenACC/Fortran] Fix mapping of optional (present|absent) arguments) Thomas Schwinge
  2019-12-05 16:04             ` Jakub Jelinek
@ 2019-12-05 16:17             ` Joseph Myers
  2019-12-05 16:24               ` Paul Koning
  2019-12-05 17:55               ` Andrew Stubbs
  2019-12-05 16:44             ` [RFC] Characters per line: from punch card (80) to line printer (132) (was: [Patch][OpenMP/OpenACC/Fortran] Fix mapping of optional (present|absent) arguments) Michael Matz
  2019-12-05 18:54             ` [RFC] Characters per line: from punch card (80) to line printer (132) Martin Sebor
  3 siblings, 2 replies; 65+ messages in thread
From: Joseph Myers @ 2019-12-05 16:17 UTC (permalink / raw)
  To: Thomas Schwinge
  Cc: gcc, gcc-patches, fortran, Jakub Jelinek, Tobias Burnus,
	Michael Meissner

On Thu, 5 Dec 2019, Thomas Schwinge wrote:

> In the relevant session at the GNU Tools Cauldron 2019, Michael Meissner
> stated that even he is not using a 80 x 24 terminal anymore, and that
> should tell us something.  ;-)
> 
> So, I formally propose that we lift this characters per line restriction
> from IBM punch card (80) to mainframe line printer (132).

I thought these line lengths were based on readability studies suggesting 
lengths that lines shorter than 80 columns were more readable?

Longer lines mean less space for multiple terminal / editor windows 
side-by-side to look at different pieces of code.  I don't think that's an 
improvement.

-- 
Joseph S. Myers
joseph@codesourcery.com

^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: [RFC] Characters per line: from punch card (80) to line printer (132) (was: [Patch][OpenMP/OpenACC/Fortran] Fix mapping of optional (present|absent) arguments)
  2019-12-05 16:17             ` Joseph Myers
@ 2019-12-05 16:24               ` Paul Koning
  2019-12-05 16:40                 ` Jeff Law
  2019-12-05 16:55                 ` [RFC] Characters per line: from punch card (80) to line printer (132) Florian Weimer
  2019-12-05 17:55               ` Andrew Stubbs
  1 sibling, 2 replies; 65+ messages in thread
From: Paul Koning @ 2019-12-05 16:24 UTC (permalink / raw)
  To: Joseph Myers
  Cc: Thomas Schwinge, gcc, gcc-patches, fortran, Jakub Jelinek,
	Tobias Burnus, Michael Meissner



> On Dec 5, 2019, at 11:17 AM, Joseph Myers <joseph@codesourcery.com> wrote:
> 
> On Thu, 5 Dec 2019, Thomas Schwinge wrote:
> 
>> In the relevant session at the GNU Tools Cauldron 2019, Michael Meissner
>> stated that even he is not using a 80 x 24 terminal anymore, and that
>> should tell us something.  ;-)
>> 
>> So, I formally propose that we lift this characters per line restriction
>> from IBM punch card (80) to mainframe line printer (132).
> 
> I thought these line lengths were based on readability studies suggesting 
> lengths that lines shorter than 80 columns were more readable?

That's certainly a general rule.  There is a reason why books aren't wide, and why newspapers have columns.  The eye can't deal well with long lines.  So while 132 column lines are certainly possible with modern computers, it doesn't mean they are desirable.

	paul

^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: [RFC] Characters per line: from punch card (80) to line printer (132) (was: [Patch][OpenMP/OpenACC/Fortran] Fix mapping of optional (present|absent) arguments)
  2019-12-05 16:24               ` Paul Koning
@ 2019-12-05 16:40                 ` Jeff Law
  2019-12-05 16:55                 ` [RFC] Characters per line: from punch card (80) to line printer (132) Florian Weimer
  1 sibling, 0 replies; 65+ messages in thread
From: Jeff Law @ 2019-12-05 16:40 UTC (permalink / raw)
  To: Paul Koning, Joseph Myers
  Cc: Thomas Schwinge, gcc, gcc-patches, fortran, Jakub Jelinek,
	Tobias Burnus, Michael Meissner

On 12/5/19 9:24 AM, Paul Koning wrote:
> 
> 
>> On Dec 5, 2019, at 11:17 AM, Joseph Myers <joseph@codesourcery.com>
>> wrote:
>> 
>> On Thu, 5 Dec 2019, Thomas Schwinge wrote:
>> 
>>> In the relevant session at the GNU Tools Cauldron 2019, Michael
>>> Meissner stated that even he is not using a 80 x 24 terminal
>>> anymore, and that should tell us something.  ;-)
>>> 
>>> So, I formally propose that we lift this characters per line
>>> restriction from IBM punch card (80) to mainframe line printer
>>> (132).
>> 
>> I thought these line lengths were based on readability studies
>> suggesting lengths that lines shorter than 80 columns were more
>> readable?
> 
> That's certainly a general rule.  There is a reason why books aren't
> wide, and why newspapers have columns.  The eye can't deal well with
> long lines.  So while 132 column lines are certainly possible with
> modern computers, it doesn't mean they are desirable.
I'd like to see the restriction relaxed.  THe 80 column limit really
presents readability problems and excessive expression wrapping to
accommodate the limit.  132 seems like a very reasonable compromise.

My biggest worry with moving to 132 columns is that it will discourage
refactoring when indention levels cause excessive wrapping.

Jeff

^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: [RFC] Characters per line: from punch card (80) to line printer (132) (was: [Patch][OpenMP/OpenACC/Fortran] Fix mapping of optional (present|absent) arguments)
  2019-12-05 15:47           ` [RFC] Characters per line: from punch card (80) to line printer (132) (was: [Patch][OpenMP/OpenACC/Fortran] Fix mapping of optional (present|absent) arguments) Thomas Schwinge
  2019-12-05 16:04             ` Jakub Jelinek
  2019-12-05 16:17             ` Joseph Myers
@ 2019-12-05 16:44             ` Michael Matz
  2019-12-05 17:03               ` Jonathan Wakely
                                 ` (3 more replies)
  2019-12-05 18:54             ` [RFC] Characters per line: from punch card (80) to line printer (132) Martin Sebor
  3 siblings, 4 replies; 65+ messages in thread
From: Michael Matz @ 2019-12-05 16:44 UTC (permalink / raw)
  To: Thomas Schwinge; +Cc: gcc, gcc-patches, fortran

Hello,

(oh a flame bait :) )

On Thu, 5 Dec 2019, Thomas Schwinge wrote:

> So, I formally propose that we lift this characters per line restriction
> from IBM punch card (80) to mainframe line printer (132).
> 
> Tasks:
> 
>   - Discussion.

I object to cluttering code in excuse for using sensible function names or 
temporaries that otherwise can help clearing up code.  Using 132-char 
lines is cluttering code:
- long lines are harder to read/grasp: vertical eye movement is easier 
  than horizontal, and source code should be optimized for 
  reading, not writing
- long lines make it impossible to have two files next to each other at a 
  comfortable font size
- long lines are incompatible with existing netiquette re emails, for 
  instance

So, at least for me, that my terminals are 80 wide (but not x24) has 
multiple reasons, and the _least_ of it is because that's what punch cards 
had.


Ciao,
Michael.

^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: [RFC] Characters per line: from punch card (80) to line printer (132)
  2019-12-05 16:24               ` Paul Koning
  2019-12-05 16:40                 ` Jeff Law
@ 2019-12-05 16:55                 ` Florian Weimer
  1 sibling, 0 replies; 65+ messages in thread
From: Florian Weimer @ 2019-12-05 16:55 UTC (permalink / raw)
  To: Paul Koning
  Cc: Joseph Myers, Thomas Schwinge, gcc, gcc-patches, fortran,
	Jakub Jelinek, Tobias Burnus, Michael Meissner

* Paul Koning:

> That's certainly a general rule.  There is a reason why books aren't
> wide, and why newspapers have columns.  The eye can't deal well with
> long lines.  So while 132 column lines are certainly possible with
> modern computers, it doesn't mean they are desirable.

If the line starts at column 40 or so, I don't think readability suffers
too much if it goes to column 100.  If it starts at column 2, then it
might be problematic.

Frequent long lines reduce the usefulness of side-by-side diff viewers.

And there are those of us who use screens in portrait mode, following
the rule that a good function is not longer than a single screen.  1080
pixels give you 8 pixels per character, which isn't that much.

Thanks,
Florian

^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: [RFC] Characters per line: from punch card (80) to line printer (132) (was: [Patch][OpenMP/OpenACC/Fortran] Fix mapping of optional (present|absent) arguments)
  2019-12-05 16:44             ` [RFC] Characters per line: from punch card (80) to line printer (132) (was: [Patch][OpenMP/OpenACC/Fortran] Fix mapping of optional (present|absent) arguments) Michael Matz
@ 2019-12-05 17:03               ` Jonathan Wakely
  2019-12-05 18:07                 ` Marek Polacek
  2019-12-05 20:06                 ` Segher Boessenkool
  2019-12-05 17:29               ` N.M. Maclaren
                                 ` (2 subsequent siblings)
  3 siblings, 2 replies; 65+ messages in thread
From: Jonathan Wakely @ 2019-12-05 17:03 UTC (permalink / raw)
  To: Michael Matz; +Cc: Thomas Schwinge, gcc, gcc-patches, fortran@gcc.gnu.org List

On Thu, 5 Dec 2019 at 16:44, Michael Matz <matz@suse.de> wrote:
>
> Hello,
>
> (oh a flame bait :) )
>
> On Thu, 5 Dec 2019, Thomas Schwinge wrote:
>
> > So, I formally propose that we lift this characters per line restriction
> > from IBM punch card (80) to mainframe line printer (132).
> >
> > Tasks:
> >
> >   - Discussion.
>
> I object to cluttering code in excuse for using sensible function names or
> temporaries that otherwise can help clearing up code.  Using 132-char
> lines is cluttering code:
> - long lines are harder to read/grasp: vertical eye movement is easier
>   than horizontal, and source code should be optimized for
>   reading, not writing
> - long lines make it impossible to have two files next to each other at a
>   comfortable font size
> - long lines are incompatible with existing netiquette re emails, for
>   instance
>
> So, at least for me, that my terminals are 80 wide (but not x24) has
> multiple reasons, and the _least_ of it is because that's what punch cards
> had.

C++17 introduces a nice feature, with rationale similar to declaring
variables in a for-loop init-statement:

if (auto var = foo(); bar(var))

The variable is only in scope for the block where you need it, just
like a for-loop.

Unfortunately nearly every time I've tried to use this recently, I've
found it's impossible in 80 columns, e.g. this from yesterday:

    if (auto __c = __builtin_memcmp(&*__first1, &*__first2, __len) <=>
0; __c != 0)
      return __c;

When you're forced to uglify every variable with a leading __ you run
out of characters pretty damn quickly.

I can either not use the feature (and have the variable defined in a
larger scope than it needs to be) or add fairly arbitrary line breaks:

            if (auto __c
            = __builtin_memcmp(&*__first1, &*__first2, __len)
            <=> 0; __c != 0)
              return __c;

or try to give the variables shorter (and less meaningful) names.
Adding line breaks or picking shorter names doesn't help readability.
So I end up not using the feature.

I'm loosely in favour of relaxing the rule for libstdc++ code. I don't
really care what the rest of GCC looks like ;-)

^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: [RFC] Characters per line: from punch card (80) to line printer (132) (was: [Patch][OpenMP/OpenACC/Fortran] Fix mapping of optional (present|absent) arguments)
  2019-12-05 16:44             ` [RFC] Characters per line: from punch card (80) to line printer (132) (was: [Patch][OpenMP/OpenACC/Fortran] Fix mapping of optional (present|absent) arguments) Michael Matz
  2019-12-05 17:03               ` Jonathan Wakely
@ 2019-12-05 17:29               ` N.M. Maclaren
  2019-12-05 20:12               ` Segher Boessenkool
  2019-12-05 20:41               ` Jason Merrill
  3 siblings, 0 replies; 65+ messages in thread
From: N.M. Maclaren @ 2019-12-05 17:29 UTC (permalink / raw)
  To: Michael Matz; +Cc: Thomas Schwinge, gcc, gcc-patches, fortran

On Dec 5 2019, Michael Matz wrote:
>
>(oh a flame bait :) )

Quite.  I shall try not to make it too much worse, but there's another point
that needs mentioning.

I find long names hard to read, with either short or long lines, especially
when combined with variants like negotiate_twisty_little_passage, and
negotiate_little_twisty_passage.  And extending line lengths will probably
encourage the use of longer names.

As people say, there are conficting requirements, but I side with you in
preferring 80 column lines.  Actually, I tend to use less, but that's
because of the (still current) frequency with which utilities make a mess
of lines exactly 80 columns long in an 80 column field.

Regards,
Nick Maclaren.

^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: [RFC] Characters per line: from punch card (80) to line printer (132)
  2019-12-05 16:17             ` Joseph Myers
  2019-12-05 16:24               ` Paul Koning
@ 2019-12-05 17:55               ` Andrew Stubbs
  2019-12-05 18:12                 ` Eric Gallager
  2019-12-05 18:22                 ` Robin Curtis
  1 sibling, 2 replies; 65+ messages in thread
From: Andrew Stubbs @ 2019-12-05 17:55 UTC (permalink / raw)
  To: Joseph Myers, Thomas Schwinge
  Cc: gcc, gcc-patches, fortran, Jakub Jelinek, Tobias Burnus,
	Michael Meissner

On 05/12/2019 16:17, Joseph Myers wrote:
> Longer lines mean less space for multiple terminal / editor windows
> side-by-side to look at different pieces of code.  I don't think that's an
> improvement.

Here's a data-point ....

My 1920 pixel-wide screen, in the default font, allows 239 columns; not 
enough for two 130-wide editors.  Especially not with line numbers and 
"gutter" columns.

On the other hand, 80 columns does tend to cause some formatting 
contortions, with long function names and deeper indentations.

I think a nice round 100 would be a good compromise.

Andrew

^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: [RFC] Characters per line: from punch card (80) to line printer (132) (was: [Patch][OpenMP/OpenACC/Fortran] Fix mapping of optional (present|absent) arguments)
  2019-12-05 17:03               ` Jonathan Wakely
@ 2019-12-05 18:07                 ` Marek Polacek
  2019-12-05 20:06                 ` Segher Boessenkool
  1 sibling, 0 replies; 65+ messages in thread
From: Marek Polacek @ 2019-12-05 18:07 UTC (permalink / raw)
  To: Jonathan Wakely
  Cc: Michael Matz, Thomas Schwinge, gcc, gcc-patches,
	fortran@gcc.gnu.org List

On Thu, Dec 05, 2019 at 05:03:43PM +0000, Jonathan Wakely wrote:
> On Thu, 5 Dec 2019 at 16:44, Michael Matz <matz@suse.de> wrote:
> >
> > Hello,
> >
> > (oh a flame bait :) )
> >
> > On Thu, 5 Dec 2019, Thomas Schwinge wrote:
> >
> > > So, I formally propose that we lift this characters per line restriction
> > > from IBM punch card (80) to mainframe line printer (132).
> > >
> > > Tasks:
> > >
> > >   - Discussion.
> >
> > I object to cluttering code in excuse for using sensible function names or
> > temporaries that otherwise can help clearing up code.  Using 132-char
> > lines is cluttering code:
> > - long lines are harder to read/grasp: vertical eye movement is easier
> >   than horizontal, and source code should be optimized for
> >   reading, not writing
> > - long lines make it impossible to have two files next to each other at a
> >   comfortable font size
> > - long lines are incompatible with existing netiquette re emails, for
> >   instance
> >
> > So, at least for me, that my terminals are 80 wide (but not x24) has
> > multiple reasons, and the _least_ of it is because that's what punch cards
> > had.
> 
> C++17 introduces a nice feature, with rationale similar to declaring
> variables in a for-loop init-statement:
> 
> if (auto var = foo(); bar(var))
> 
> The variable is only in scope for the block where you need it, just
> like a for-loop.
> 
> Unfortunately nearly every time I've tried to use this recently, I've
> found it's impossible in 80 columns, e.g. this from yesterday:
> 
>     if (auto __c = __builtin_memcmp(&*__first1, &*__first2, __len) <=>
> 0; __c != 0)
>       return __c;
> 
> When you're forced to uglify every variable with a leading __ you run
> out of characters pretty damn quickly.
> 
> I can either not use the feature (and have the variable defined in a
> larger scope than it needs to be) or add fairly arbitrary line breaks:
> 
>             if (auto __c
>             = __builtin_memcmp(&*__first1, &*__first2, __len)
>             <=> 0; __c != 0)
>               return __c;
> 
> or try to give the variables shorter (and less meaningful) names.
> Adding line breaks or picking shorter names doesn't help readability.
> So I end up not using the feature.
> 
> I'm loosely in favour of relaxing the rule for libstdc++ code. I don't
> really care what the rest of GCC looks like ;-)

Not using such a nice feature just because of formatting sounds really
shameful.  Would the compromise of 100 chars make things any better here?

Marek

^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: [RFC] Characters per line: from punch card (80) to line printer (132)
  2019-12-05 17:55               ` Andrew Stubbs
@ 2019-12-05 18:12                 ` Eric Gallager
  2019-12-05 18:22                 ` Robin Curtis
  1 sibling, 0 replies; 65+ messages in thread
From: Eric Gallager @ 2019-12-05 18:12 UTC (permalink / raw)
  To: Andrew Stubbs
  Cc: Joseph Myers, Thomas Schwinge, gcc, gcc-patches, fortran,
	Jakub Jelinek, Tobias Burnus, Michael Meissner

On 12/5/19, Andrew Stubbs <ams@codesourcery.com> wrote:
> On 05/12/2019 16:17, Joseph Myers wrote:
>> Longer lines mean less space for multiple terminal / editor windows
>> side-by-side to look at different pieces of code.  I don't think that's
>> an
>> improvement.
>
> Here's a data-point ....
>
> My 1920 pixel-wide screen, in the default font, allows 239 columns; not
> enough for two 130-wide editors.  Especially not with line numbers and
> "gutter" columns.
>
> On the other hand, 80 columns does tend to cause some formatting
> contortions, with long function names and deeper indentations.
>
> I think a nice round 100 would be a good compromise.

Here's mine:

My 1280 pixel-wide screen allows 179 columns, which comes to 89.5
columns when divided by 2. I think rounding up to 90 columns would be
a good compromise, although if that's too small, 100 is good as well.

>
> Andrew
>

^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: [RFC] Characters per line: from punch card (80) to line printer (132)
  2019-12-05 17:55               ` Andrew Stubbs
  2019-12-05 18:12                 ` Eric Gallager
@ 2019-12-05 18:22                 ` Robin Curtis
  2019-12-05 19:16                   ` James Secan
  2019-12-06  9:22                   ` Andrew Stubbs
  1 sibling, 2 replies; 65+ messages in thread
From: Robin Curtis @ 2019-12-05 18:22 UTC (permalink / raw)
  To: Andrew Stubbs
  Cc: Joseph Myers, Thomas Schwinge, gcc, gcc-patches, fortran,
	Jakub Jelinek, Tobias Burnus, Michael Meissner

My IBM Selectric golfball electronic printer only does 90 characters on A4 in portrait mode………(at 10 cps) 

(as for my all electric TELEX Teleprinter machine !) 

Is this debate for real ?!  - or is this a Christmas spoof ? 

External observer…..keep up the great work. :)

(while I punch out a few more 80 column cards). 



> On 5 Dec 2019, at 17:55, Andrew Stubbs <ams@codesourcery.com> wrote:
> 
> On 05/12/2019 16:17, Joseph Myers wrote:
>> Longer lines mean less space for multiple terminal / editor windows
>> side-by-side to look at different pieces of code.  I don't think that's an
>> improvement.
> 
> Here's a data-point ....
> 
> My 1920 pixel-wide screen, in the default font, allows 239 columns; not enough for two 130-wide editors.  Especially not with line numbers and "gutter" columns.
> 
> On the other hand, 80 columns does tend to cause some formatting contortions, with long function names and deeper indentations.
> 
> I think a nice round 100 would be a good compromise.
> 
> Andrew


^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: [RFC] Characters per line: from punch card (80) to line printer (132)
  2019-12-05 15:47           ` [RFC] Characters per line: from punch card (80) to line printer (132) (was: [Patch][OpenMP/OpenACC/Fortran] Fix mapping of optional (present|absent) arguments) Thomas Schwinge
                               ` (2 preceding siblings ...)
  2019-12-05 16:44             ` [RFC] Characters per line: from punch card (80) to line printer (132) (was: [Patch][OpenMP/OpenACC/Fortran] Fix mapping of optional (present|absent) arguments) Michael Matz
@ 2019-12-05 18:54             ` Martin Sebor
  2019-12-05 20:32               ` Segher Boessenkool
  3 siblings, 1 reply; 65+ messages in thread
From: Martin Sebor @ 2019-12-05 18:54 UTC (permalink / raw)
  To: Thomas Schwinge, gcc
  Cc: gcc-patches, fortran, Jakub Jelinek, Tobias Burnus, Michael Meissner

On 12/5/19 8:46 AM, Thomas Schwinge wrote:
> Hi!
> 
> ;-P Jakub, thanks for furnishing me a fit occasion here:
> 
> On 2019-12-05T16:15:15+0100, Jakub Jelinek <jakub@redhat.com> wrote:
>> [...] much more indented though, but you could
>> use a temporary, like:
>> 		      tree nullarg = null_pointer_node;
> 
> I object to cluttering the code by introducing temporary variables/names
> just for the sake of a few characters of screen width.  Even if located
> close lexically, when reading the following code you still have to trace
> back from the 'nullarg' usage to its 'null_pointer_node' definition in
> order to figure out what a 'nullarg' might be:
> 
>> 		      if (present)
>> 			ptr
>> 			  = gfc_build_conditional_assign_expr (block, present,
>> 							       ptr, nullarg);

The snippet of code above looks like it might be the symptom
of another common problem: deeply nested conditionals, case
statements, or loops in very large functions.  Those usually
make it much harder to follow code than local variables or
expressions that are broken up to fit the width limit.
Shorter functions typically also means fewer local variables.

One thing I find improves readability in functions with many
local variables is declaring const those that don't change
after initialization.  That also enforces the initialization-
on-declaration coding style, and can result in more efficient
code.

Another solution that might help in this context is default
function arguments: if the last argument may be null, making
it the default in the function declaration avoids having to
pass it explicitly.

> 
>> Another option would be shorten the name of the function, say
>> s/conditional/cond/.

As long as it doesn't compromise readability this sounds like
a good suggestion for a change to the function above.  _cond_
is no less clear or descriptive than _conditional_, similarly
to _expr vs _expression.

> 
> Likewise I object to "crippling" identifier names like that just for the
> sake of a few characters of screen width.  (Here of course, "cond", or
> the existing "expr" might be fine abbreviations, but my point is about
> the general case.)
> 
>> There were some discussions about lifting the 80 column restriction and bump
>> it to something like +-130, but nothing happened yet.
> 
> Indeed.  :-)
> 
> In the relevant session at the GNU Tools Cauldron 2019, Michael Meissner
> stated that even he is not using a 80 x 24 terminal anymore, and that
> should tell us something.  ;-)
> 
> So, I formally propose that we lift this characters per line restriction
> from IBM punch card (80) to mainframe line printer (132).

I'm not a fan of rigid rules, especially those that are subject
to personal style preferences.  At the same time I wouldn't like
to see lines become as long as this as the norm.  As others,
I have windows om my desktop arranged in a way to maximize screen
real estate: three columns of editor/debugger and a couple of
terminals on of top of the other.  They only fit because they're
all 80 characters wide.  But more important:

> deep
> indentation often is a sign that code should be split out into a separate
> function, for example.

Exactly.

Martin

   My point is just to avoid things like the two
> examples cited above.
> 
> Also, I'm not proposing any mass-reformatting of the existing code, or
> re-writing all "expr" into "expression".
> 
> Tasks:
> 
>    - Discussion.
>    - Get agreement/make a decision (by means still to be determined).
>    - Put suitable Emacs/Vim configuration files into the source tree?
>    - Update coding style guidelines.
> 
> 
> Grüße
>   Thomas
> 

^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: [RFC] Characters per line: from punch card (80) to line printer (132)
  2019-12-05 18:22                 ` Robin Curtis
@ 2019-12-05 19:16                   ` James Secan
  2019-12-06  9:22                   ` Andrew Stubbs
  1 sibling, 0 replies; 65+ messages in thread
From: James Secan @ 2019-12-05 19:16 UTC (permalink / raw)
  To: Robin Curtis, Andrew Stubbs, Joseph Myers, Thomas Schwinge, gcc,
	gcc-patches, fortran, Jakub Jelinek, Tobias Burnus,
	Michael Meissner

All,

As a certified Old Guy (coding in FORTRAN since 1967) my default mode is to stop at 72 characters.  It would be nice to push the max out a bit, but I’ll most likely keep my lines (and my function and variable names!) short.  As always, brevity is the soul of wit.

And yes, please keep up the good work.

Jim
3222 NE 89th St
Seattle, WA 98115
(206) 430-0109

> On Dec 5, 2019, at 10:21 AM, Robin Curtis <Curtis@geoscience.co.uk> wrote:
> 
> Is this debate for real ?!  - or is this a Christmas spoof ? 
> 
> External observer…..keep up the great work. :)
> 
> (while I punch out a few more 80 column cards). 

^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: [RFC] Characters per line: from punch card (80) to line printer (132) (was: [Patch][OpenMP/OpenACC/Fortran] Fix mapping of optional (present|absent) arguments)
  2019-12-05 17:03               ` Jonathan Wakely
  2019-12-05 18:07                 ` Marek Polacek
@ 2019-12-05 20:06                 ` Segher Boessenkool
  2019-12-05 20:38                   ` Marek Polacek
  2019-12-05 20:56                   ` Jonathan Wakely
  1 sibling, 2 replies; 65+ messages in thread
From: Segher Boessenkool @ 2019-12-05 20:06 UTC (permalink / raw)
  To: Jonathan Wakely
  Cc: Michael Matz, Thomas Schwinge, gcc, gcc-patches,
	fortran@gcc.gnu.org List

Hi!

On Thu, Dec 05, 2019 at 05:03:43PM +0000, Jonathan Wakely wrote:
> C++17 introduces a nice feature, with rationale similar to declaring
> variables in a for-loop init-statement:
> 
> if (auto var = foo(); bar(var))

Similar to GNU C statement expressions, which are *also* only a good
idea to use in limited cases.

> The variable is only in scope for the block where you need it, just
> like a for-loop.
> 
> Unfortunately nearly every time I've tried to use this recently, I've
> found it's impossible in 80 columns, e.g. this from yesterday:
> 
>     if (auto __c = __builtin_memcmp(&*__first1, &*__first2, __len) <=>
> 0; __c != 0)
>       return __c;
> 
> When you're forced to uglify every variable with a leading __ you run
> out of characters pretty damn quickly.

If using this "nice feature" forces you to uglify your code, then maybe
it is not such a nice feature, and you should not use it.

If you have issues with scoping your functions are WAY too long already.


Segher

^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: [RFC] Characters per line: from punch card (80) to line printer (132) (was: [Patch][OpenMP/OpenACC/Fortran] Fix mapping of optional (present|absent) arguments)
  2019-12-05 16:44             ` [RFC] Characters per line: from punch card (80) to line printer (132) (was: [Patch][OpenMP/OpenACC/Fortran] Fix mapping of optional (present|absent) arguments) Michael Matz
  2019-12-05 17:03               ` Jonathan Wakely
  2019-12-05 17:29               ` N.M. Maclaren
@ 2019-12-05 20:12               ` Segher Boessenkool
  2019-12-05 20:41               ` Jason Merrill
  3 siblings, 0 replies; 65+ messages in thread
From: Segher Boessenkool @ 2019-12-05 20:12 UTC (permalink / raw)
  To: Michael Matz; +Cc: Thomas Schwinge, gcc, gcc-patches, fortran

On Thu, Dec 05, 2019 at 04:44:21PM +0000, Michael Matz wrote:
> (oh a flame bait :) )

I will blissfully ignore that warning.

> On Thu, 5 Dec 2019, Thomas Schwinge wrote:
> I object to cluttering code in excuse for using sensible function names or 
> temporaries that otherwise can help clearing up code.  Using 132-char 
> lines is cluttering code:
> - long lines are harder to read/grasp: vertical eye movement is easier 
>   than horizontal, and source code should be optimized for 
>   reading, not writing
> - long lines make it impossible to have two files next to each other at a 
>   comfortable font size
> - long lines are incompatible with existing netiquette re emails, for 
>   instance
> 
> So, at least for me, that my terminals are 80 wide (but not x24) has 
> multiple reasons, and the _least_ of it is because that's what punch cards 
> had.

I agree with all of this.

If you have a hard time writing nicely readable code in 80 columns, you
will have a much harder time still using more columns.  80 is somewhat
too long already (~60 is better), but we have indents in source code,
so that's alright.  And you should not indent that far, so this all
works out splendidly.


Segher

^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: [RFC] Characters per line: from punch card (80) to line printer (132) (was: [Patch][OpenMP/OpenACC/Fortran] Fix mapping of optional (present|absent) arguments)
  2019-12-05 16:04             ` Jakub Jelinek
@ 2019-12-05 20:21               ` Segher Boessenkool
  0 siblings, 0 replies; 65+ messages in thread
From: Segher Boessenkool @ 2019-12-05 20:21 UTC (permalink / raw)
  To: Jakub Jelinek
  Cc: Thomas Schwinge, gcc, gcc-patches, fortran, Tobias Burnus,
	Michael Meissner

On Thu, Dec 05, 2019 at 05:04:12PM +0100, Jakub Jelinek wrote:
> On Thu, Dec 05, 2019 at 04:46:45PM +0100, Thomas Schwinge wrote:
> > On 2019-12-05T16:15:15+0100, Jakub Jelinek <jakub@redhat.com> wrote:
> > > [...] much more indented though, but you could
> > > use a temporary, like:
> > > 		      tree nullarg = null_pointer_node;
> > 
> > I object to cluttering the code by introducing temporary variables/names
> > just for the sake of a few characters of screen width.  Even if located
> > close lexically, when reading the following code you still have to trace
> > back from the 'nullarg' usage to its 'null_pointer_node' definition in
> > order to figure out what a 'nullarg' might be:
> > 
> > > 		      if (present)
> > > 			ptr
> > > 			  = gfc_build_conditional_assign_expr (block, present,
> > > 							       ptr, nullarg);
> > 
> > > Another option would be shorten the name of the function, say
> > > s/conditional/cond/.
> > 
> > Likewise I object to "crippling" identifier names like that just for the
> > sake of a few characters of screen width.  (Here of course, "cond", or
> > the existing "expr" might be fine abbreviations, but my point is about
> > the general case.)
> 
> The point about temporaries is general, and I believe they actually make
> code much more readable.  Mostly about coding style like:
> 	t = fold_build2_loc (loc, code, fold_build2_loc (loc, code2,
> 							 something1,
> 							 something2),
> 			     fold_build2_loc (loc, code3, something3,
> 					      something4));
> vs.
> 	tree op1 = fold_build2_loc (loc, code2, something1, something2);
> 	tree op2 = fold_build2_loc (loc, code3, something3, something4);
> 	t = fold_build2_loc (loc, code, op1, op2);

Yes.  And the names, even if they do not say much, *do* say enough to
help comprehending the code.  They help structure it.

> The above case is extreme in both being indented quite a lot (general rule
> is to consider outlining something into a function then)

I hope you mean actual factoring, not just outlining :-)  If you pick good
factors you can give them good names, too.

Good names help reading the code.  And on the other hand, when it is hard
to come up with a good name for a piece of code, it is probably not chosen
as a good factor anyway!

> and using
> way too long function names.  If you look at the earlier suggestion where
> the code is indented reasonably, using the temporary there makes the code more
> readable and shorter.

Yup.


Segher

^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: [RFC] Characters per line: from punch card (80) to line printer (132)
  2019-12-05 18:54             ` [RFC] Characters per line: from punch card (80) to line printer (132) Martin Sebor
@ 2019-12-05 20:32               ` Segher Boessenkool
  0 siblings, 0 replies; 65+ messages in thread
From: Segher Boessenkool @ 2019-12-05 20:32 UTC (permalink / raw)
  To: Martin Sebor
  Cc: Thomas Schwinge, gcc, gcc-patches, fortran, Jakub Jelinek,
	Tobias Burnus, Michael Meissner

On Thu, Dec 05, 2019 at 11:54:04AM -0700, Martin Sebor wrote:
> >>		      if (present)
> >>			ptr
> >>			  = gfc_build_conditional_assign_expr (block, 
> >>			  present,
> >>							       ptr, nullarg);
> 
> The snippet of code above looks like it might be the symptom
> of another common problem: deeply nested conditionals, case
> statements, or loops in very large functions.  Those usually
> make it much harder to follow code than local variables or
> expressions that are broken up to fit the width limit.
> Shorter functions typically also means fewer local variables.

Yes, and you only get problems that you do not know which var is which,
or you do not know what value it is set to because it was set some 2800
(or 40 or whatever) lines ago, in WAY too long functions.

All those problems do not exist in well-factored code.  The point is not
to have short routines: the point is to not have too much (external)
complexity per routine.  A routine should ideally only do one thing, and
its name should describe what it does.


Segher

^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: [RFC] Characters per line: from punch card (80) to line printer (132) (was: [Patch][OpenMP/OpenACC/Fortran] Fix mapping of optional (present|absent) arguments)
  2019-12-05 20:06                 ` Segher Boessenkool
@ 2019-12-05 20:38                   ` Marek Polacek
  2019-12-05 22:02                     ` Segher Boessenkool
  2019-12-05 20:56                   ` Jonathan Wakely
  1 sibling, 1 reply; 65+ messages in thread
From: Marek Polacek @ 2019-12-05 20:38 UTC (permalink / raw)
  To: Segher Boessenkool
  Cc: Jonathan Wakely, Michael Matz, Thomas Schwinge, gcc, gcc-patches,
	fortran@gcc.gnu.org List

On Thu, Dec 05, 2019 at 02:06:50PM -0600, Segher Boessenkool wrote:
> Hi!
> 
> On Thu, Dec 05, 2019 at 05:03:43PM +0000, Jonathan Wakely wrote:
> > C++17 introduces a nice feature, with rationale similar to declaring
> > variables in a for-loop init-statement:
> > 
> > if (auto var = foo(); bar(var))
> 
> Similar to GNU C statement expressions, which are *also* only a good
> idea to use in limited cases.
> 
> > The variable is only in scope for the block where you need it, just
> > like a for-loop.
> > 
> > Unfortunately nearly every time I've tried to use this recently, I've
> > found it's impossible in 80 columns, e.g. this from yesterday:
> > 
> >     if (auto __c = __builtin_memcmp(&*__first1, &*__first2, __len) <=>
> > 0; __c != 0)
> >       return __c;
> > 
> > When you're forced to uglify every variable with a leading __ you run
> > out of characters pretty damn quickly.
> 
> If using this "nice feature" forces you to uglify your code, then maybe
> it is not such a nice feature, and you should not use it.

I disagree, it is a nice feature, without quotes.  It's Good Style not to
leak variables into enclosing scopes.

> If you have issues with scoping your functions are WAY too long already.

I don't think that's the case here.

--
Marek Polacek • Red Hat, Inc. • 300 A St, Boston, MA

^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: [RFC] Characters per line: from punch card (80) to line printer (132) (was: [Patch][OpenMP/OpenACC/Fortran] Fix mapping of optional (present|absent) arguments)
  2019-12-05 16:44             ` [RFC] Characters per line: from punch card (80) to line printer (132) (was: [Patch][OpenMP/OpenACC/Fortran] Fix mapping of optional (present|absent) arguments) Michael Matz
                                 ` (2 preceding siblings ...)
  2019-12-05 20:12               ` Segher Boessenkool
@ 2019-12-05 20:41               ` Jason Merrill
  3 siblings, 0 replies; 65+ messages in thread
From: Jason Merrill @ 2019-12-05 20:41 UTC (permalink / raw)
  To: Michael Matz; +Cc: Thomas Schwinge, gcc Mailing List, gcc-patches List, fortran

On Thu, Dec 5, 2019 at 11:51 AM Michael Matz <matz@suse.de> wrote:

> Hello,
>
> (oh a flame bait :) )
>
> On Thu, 5 Dec 2019, Thomas Schwinge wrote:
>
> > So, I formally propose that we lift this characters per line restriction
> > from IBM punch card (80) to mainframe line printer (132).
> >
> > Tasks:
> >
> >   - Discussion.
>
> I object to cluttering code in excuse for using sensible function names or
> temporaries that otherwise can help clearing up code.  Using 132-char
> lines is cluttering code:
> - long lines are harder to read/grasp: vertical eye movement is easier
>   than horizontal, and source code should be optimized for
>   reading, not writing
> - long lines make it impossible to have two files next to each other at a
>   comfortable font size
> - long lines are incompatible with existing netiquette re emails, for
>   instance
>
> So, at least for me, that my terminals are 80 wide (but not x24) has
> multiple reasons, and the _least_ of it is because that's what punch cards
> had.
>

Agreed.  I work with two side-by-side terminals, one 80x50 and the other as
wide as fits in the rest of the screen, which currently happens to be
111x50.

Jason

^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: [RFC] Characters per line: from punch card (80) to line printer (132) (was: [Patch][OpenMP/OpenACC/Fortran] Fix mapping of optional (present|absent) arguments)
  2019-12-05 20:06                 ` Segher Boessenkool
  2019-12-05 20:38                   ` Marek Polacek
@ 2019-12-05 20:56                   ` Jonathan Wakely
  2019-12-05 22:19                     ` Segher Boessenkool
  1 sibling, 1 reply; 65+ messages in thread
From: Jonathan Wakely @ 2019-12-05 20:56 UTC (permalink / raw)
  To: Segher Boessenkool
  Cc: Michael Matz, Thomas Schwinge, gcc, gcc-patches,
	fortran@gcc.gnu.org List

On Thu, 5 Dec 2019 at 20:07, Segher Boessenkool
<segher@kernel.crashing.org> wrote:
>
> Hi!
>
> On Thu, Dec 05, 2019 at 05:03:43PM +0000, Jonathan Wakely wrote:
> > C++17 introduces a nice feature, with rationale similar to declaring
> > variables in a for-loop init-statement:
> >
> > if (auto var = foo(); bar(var))
>
> Similar to GNU C statement expressions, which are *also* only a good
> idea to use in limited cases.
>
> > The variable is only in scope for the block where you need it, just
> > like a for-loop.
> >
> > Unfortunately nearly every time I've tried to use this recently, I've
> > found it's impossible in 80 columns, e.g. this from yesterday:
> >
> >     if (auto __c = __builtin_memcmp(&*__first1, &*__first2, __len) <=>
> > 0; __c != 0)
> >       return __c;
> >
> > When you're forced to uglify every variable with a leading __ you run
> > out of characters pretty damn quickly.
>
> If using this "nice feature" forces you to uglify your code, then maybe
> it is not such a nice feature, and you should not use it.

The uglification has absolutely nothing to do with the 'if'
init-statement feature, all code in libstdc++ headers has to be
uglified, always. Blame the C preprocessor for that, not C++ features.

My point is that 80 characters runs out quicker when 10% of it goes on
visual noise that's only needed because the C preprocessor means we
can't have nice names.

> If you have issues with scoping your functions are WAY too long already.

I don't have issues with scoping, it's just good practice to limit the
scope to the minimum necessary.

The example I'm talking about is:
https://gcc.gnu.org/git/?p=gcc.git;a=blob;f=libstdc%2B%2B-v3/include/bits/stl_algobase.h;h=a2fd306e6d0cca579b510148ba1a7089e2b2f3a2;hb=HEAD#l1499

That function is 46 lines long, including a micro-optimisation to use
memcmpy when appropriate. About 15% of that is on assertions to help
users debug their mistakes. Another five lines are the compile-time
if-constexpr checks to decide when the optimisation is appropriate,
which result in deep nesting, but not because of any complex if-else
branches. It could be nested less deeply to reduce indentation by 4
spaces, but that would result in more template instantiations for
users, which would take more time and memory to compile. When you have
a million users including the header in every C++ program, little
things like that help. So the code is written in an unidiomatic way to
optimise for compilation speed, not readability.

But the end result is that the call to __min_cmp is indented about 25%
of the way into the available space, and that the FIRST line of
executable code in the function. The code is not way too long, and
writing it differently would compile slower. The constraints that
apply to that code are quite different to the internals of GCC, which
most users never see or even compile themselves.

(Yes, maybe libstdc++ should stop indenting everything by 2 columns
when it's inside a namespace, given that almost everything is inside
at least one level of namespace ... that might be a good idea even if
the column limit is extended to 100 or 132, but we'll still have all
the __ prefixes eating up space.)

^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: [RFC] Characters per line: from punch card (80) to line printer (132) (was: [Patch][OpenMP/OpenACC/Fortran] Fix mapping of optional (present|absent) arguments)
  2019-12-05 20:38                   ` Marek Polacek
@ 2019-12-05 22:02                     ` Segher Boessenkool
  0 siblings, 0 replies; 65+ messages in thread
From: Segher Boessenkool @ 2019-12-05 22:02 UTC (permalink / raw)
  To: Marek Polacek
  Cc: Jonathan Wakely, Michael Matz, Thomas Schwinge, gcc, gcc-patches,
	fortran@gcc.gnu.org List

On Thu, Dec 05, 2019 at 03:38:15PM -0500, Marek Polacek wrote:
> On Thu, Dec 05, 2019 at 02:06:50PM -0600, Segher Boessenkool wrote:
> > > When you're forced to uglify every variable with a leading __ you run
> > > out of characters pretty damn quickly.
> > 
> > If using this "nice feature" forces you to uglify your code, then maybe
> > it is not such a nice feature, and you should not use it.
> 
> I disagree, it is a nice feature, without quotes.  It's Good Style not to
> leak variables into enclosing scopes.

It *is* a quote, from Jonathan's mail.

Why is this Good Style?  (And according to who?)

> > If you have issues with scoping your functions are WAY too long already.
> 
> I don't think that's the case here.

Then it does not hurt to have a local that is visible in slightly longer
scope than necessary.

Simpler code is better code.


Segher

^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: [RFC] Characters per line: from punch card (80) to line printer (132) (was: [Patch][OpenMP/OpenACC/Fortran] Fix mapping of optional (present|absent) arguments)
  2019-12-05 20:56                   ` Jonathan Wakely
@ 2019-12-05 22:19                     ` Segher Boessenkool
  2019-12-05 22:34                       ` Jonathan Wakely
  2019-12-05 22:37                       ` Jonathan Wakely
  0 siblings, 2 replies; 65+ messages in thread
From: Segher Boessenkool @ 2019-12-05 22:19 UTC (permalink / raw)
  To: Jonathan Wakely
  Cc: Michael Matz, Thomas Schwinge, gcc, gcc-patches,
	fortran@gcc.gnu.org List

On Thu, Dec 05, 2019 at 08:56:35PM +0000, Jonathan Wakely wrote:
> On Thu, 5 Dec 2019 at 20:07, Segher Boessenkool
> <segher@kernel.crashing.org> wrote:
> > On Thu, Dec 05, 2019 at 05:03:43PM +0000, Jonathan Wakely wrote:
> > > C++17 introduces a nice feature, with rationale similar to declaring
> > > variables in a for-loop init-statement:

> > > Unfortunately nearly every time I've tried to use this recently, I've
> > > found it's impossible in 80 columns, e.g. this from yesterday:
> > >
> > >     if (auto __c = __builtin_memcmp(&*__first1, &*__first2, __len) <=>
> > > 0; __c != 0)
> > >       return __c;
> > >
> > > When you're forced to uglify every variable with a leading __ you run
> > > out of characters pretty damn quickly.
> >
> > If using this "nice feature" forces you to uglify your code, then maybe
> > it is not such a nice feature, and you should not use it.
> 
> The uglification has absolutely nothing to do with the 'if'
> init-statement feature, all code in libstdc++ headers has to be
> uglified, always. Blame the C preprocessor for that, not C++ features.
> 
> My point is that 80 characters runs out quicker when 10% of it goes on
> visual noise that's only needed because the C preprocessor means we
> can't have nice names.

(Not sure where the preprocessor comes in, these underscores are just to
satisfy language rules afaics, but maybe you mean something else?)

Or you could write

    auto __c = (__builtin_memcmp(&*__first1, &*__first2, __len) <=> 0);
    if (__c)
      return __c;

which is much easier to read, to my eyes anyway.  And it is exactly the
same for the compiler.

Wrapping everything inside-out just for the artificial goal of having
things defined in slightly tighter scopes feels futile.


Segher

^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: [RFC] Characters per line: from punch card (80) to line printer (132) (was: [Patch][OpenMP/OpenACC/Fortran] Fix mapping of optional (present|absent) arguments)
  2019-12-05 22:19                     ` Segher Boessenkool
@ 2019-12-05 22:34                       ` Jonathan Wakely
  2019-12-05 22:37                       ` Jonathan Wakely
  1 sibling, 0 replies; 65+ messages in thread
From: Jonathan Wakely @ 2019-12-05 22:34 UTC (permalink / raw)
  To: Segher Boessenkool
  Cc: Michael Matz, Thomas Schwinge, gcc, gcc-patches,
	fortran@gcc.gnu.org List

On Thu, 5 Dec 2019 at 22:19, Segher Boessenkool wrote:
>
> On Thu, Dec 05, 2019 at 08:56:35PM +0000, Jonathan Wakely wrote:
> > On Thu, 5 Dec 2019 at 20:07, Segher Boessenkool
> > <segher@kernel.crashing.org> wrote:
> > > On Thu, Dec 05, 2019 at 05:03:43PM +0000, Jonathan Wakely wrote:
> > > > C++17 introduces a nice feature, with rationale similar to declaring
> > > > variables in a for-loop init-statement:
>
> > > > Unfortunately nearly every time I've tried to use this recently, I've
> > > > found it's impossible in 80 columns, e.g. this from yesterday:
> > > >
> > > >     if (auto __c = __builtin_memcmp(&*__first1, &*__first2, __len) <=>
> > > > 0; __c != 0)
> > > >       return __c;
> > > >
> > > > When you're forced to uglify every variable with a leading __ you run
> > > > out of characters pretty damn quickly.
> > >
> > > If using this "nice feature" forces you to uglify your code, then maybe
> > > it is not such a nice feature, and you should not use it.
> >
> > The uglification has absolutely nothing to do with the 'if'
> > init-statement feature, all code in libstdc++ headers has to be
> > uglified, always. Blame the C preprocessor for that, not C++ features.
> >
> > My point is that 80 characters runs out quicker when 10% of it goes on
> > visual noise that's only needed because the C preprocessor means we
> > can't have nice names.
>
> (Not sure where the preprocessor comes in, these underscores are just to
> satisfy language rules afaics, but maybe you mean something else?)

The language rules are only necessary because of the preprocessor.
Users can define macros with names like "pred" and "cmp" before
including any standard library header, and because macros don't
respect lexical scope, that would break any standard library code
using "pred" and "cmp". So the std::lib has to use reserved names.

It's entirely due to the preprocessor that we can't use sane names for
local variables, or for any implementation detail in a header (unlike
in C, our helper types and functions are in a namespace so won't
collide with users' types and functions, but we still have to use
reserved names because the preprocessor doesn't respect namespaces).

^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: [RFC] Characters per line: from punch card (80) to line printer (132) (was: [Patch][OpenMP/OpenACC/Fortran] Fix mapping of optional (present|absent) arguments)
  2019-12-05 22:19                     ` Segher Boessenkool
  2019-12-05 22:34                       ` Jonathan Wakely
@ 2019-12-05 22:37                       ` Jonathan Wakely
  2019-12-05 23:02                         ` Segher Boessenkool
  1 sibling, 1 reply; 65+ messages in thread
From: Jonathan Wakely @ 2019-12-05 22:37 UTC (permalink / raw)
  To: Segher Boessenkool
  Cc: Michael Matz, Thomas Schwinge, gcc, gcc-patches,
	fortran@gcc.gnu.org List

On Thu, 5 Dec 2019 at 22:19, Segher Boessenkool wrote:
> Or you could write
>
>     auto __c = (__builtin_memcmp(&*__first1, &*__first2, __len) <=> 0);
>     if (__c)
>       return __c;
>
> which is much easier to read, to my eyes anyway.  And it is exactly the
> same for the compiler.

In this case yes, but not in general.

Given:

auto x = foo();
if (bar(x))
{ }
some_type y;

The destructor of x won't run until after y has been destroyed. That's
not at all identical to:

if (auto x = foo(); bar(x))
{ }
some_type y;

Please don't try to tell me how C++ works :-)

^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: [RFC] Characters per line: from punch card (80) to line printer (132) (was: [Patch][OpenMP/OpenACC/Fortran] Fix mapping of optional (present|absent) arguments)
  2019-12-05 22:37                       ` Jonathan Wakely
@ 2019-12-05 23:02                         ` Segher Boessenkool
  0 siblings, 0 replies; 65+ messages in thread
From: Segher Boessenkool @ 2019-12-05 23:02 UTC (permalink / raw)
  To: Jonathan Wakely
  Cc: Michael Matz, Thomas Schwinge, gcc, gcc-patches,
	fortran@gcc.gnu.org List

On Thu, Dec 05, 2019 at 10:37:33PM +0000, Jonathan Wakely wrote:
> On Thu, 5 Dec 2019 at 22:19, Segher Boessenkool wrote:
> > Or you could write
> >
> >     auto __c = (__builtin_memcmp(&*__first1, &*__first2, __len) <=> 0);
> >     if (__c)
> >       return __c;
> >
> > which is much easier to read, to my eyes anyway.  And it is exactly the
> > same for the compiler.
> 
> In this case yes, but not in general.
> 
> Given:
> 
> auto x = foo();
> if (bar(x))
> { }
> some_type y;
> 
> The destructor of x won't run until after y has been destroyed. That's
> not at all identical to:
> 
> if (auto x = foo(); bar(x))
> { }
> some_type y;
> 
> Please don't try to tell me how C++ works :-)

I don't, I wouldn't even *know* that.  But this is just the same as in C,
and I do know how to write good C code.

I don't think doing non-trivial things with constructors and destructors
(or anything else!) implicitly is a good idea at all, but that's an
altogether different subject.


Segher

^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: [RFC] Characters per line: from punch card (80) to line printer (132)
  2019-12-05 18:22                 ` Robin Curtis
  2019-12-05 19:16                   ` James Secan
@ 2019-12-06  9:22                   ` Andrew Stubbs
  1 sibling, 0 replies; 65+ messages in thread
From: Andrew Stubbs @ 2019-12-06  9:22 UTC (permalink / raw)
  To: Robin Curtis
  Cc: Joseph Myers, Thomas Schwinge, gcc, gcc-patches, fortran,
	Jakub Jelinek, Tobias Burnus, Michael Meissner

On 05/12/2019 18:21, Robin Curtis wrote:
> My IBM Selectric golfball electronic printer only does 90 characters on A4 in portrait mode………(at 10 cps)
> 
> (as for my all electric TELEX Teleprinter machine !)
> 
> Is this debate for real ?!  - or is this a Christmas spoof ?

I can't speak for the debate, but the pain is real.

Andrew

^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: [Patch][OpenMP/OpenACC/Fortran] Fix mapping of optional (present|absent) arguments
  2019-11-20 13:11       ` [Patch][OpenMP/OpenACC/Fortran] Fix mapping of optional (present|absent) arguments Tobias Burnus
  2019-11-29 12:17         ` Tobias Burnus
  2019-12-05 15:16         ` Jakub Jelinek
@ 2019-12-07 14:49         ` Thomas Schwinge
  2019-12-11 10:52           ` Tobias Burnus
  2 siblings, 1 reply; 65+ messages in thread
From: Thomas Schwinge @ 2019-12-07 14:49 UTC (permalink / raw)
  To: Tobias Burnus; +Cc: gcc-patches, fortran, Jakub Jelinek

[-- Attachment #1: Type: text/plain, Size: 4931 bytes --]

Hi Tobias!

On 2019-11-20T14:06:18+0100, Tobias Burnus <tobias@codesourcery.com> wrote:
> This patch does two things regarding explicit and automatical variable 
> mapping to offloaded devices:

Thanks!


> Compared to the previous patch set,** I added several OpenMP test cases 
> – and fixed the fallout.

I'm seeing:

    PASS: libgomp.fortran/use_device_addr-3.f90   -O0  (test for excess errors)
    PASS: libgomp.fortran/use_device_addr-3.f90   -O0  execution test
    PASS: libgomp.fortran/use_device_addr-3.f90   -O1  (test for excess errors)
    [-PASS:-]{+FAIL:+} libgomp.fortran/use_device_addr-3.f90   -O1  execution test
    PASS: libgomp.fortran/use_device_addr-3.f90   -O2  (test for excess errors)
    [-PASS:-]{+FAIL:+} libgomp.fortran/use_device_addr-3.f90   -O2  execution test
    PASS: libgomp.fortran/use_device_addr-3.f90   -O3 -fomit-frame-pointer -funroll-loops -fpeel-loops -ftracer -finline-functions  (test for excess errors)
    [-PASS:-]{+FAIL:+} libgomp.fortran/use_device_addr-3.f90   -O3 -fomit-frame-pointer -funroll-loops -fpeel-loops -ftracer -finline-functions  execution test
    PASS: libgomp.fortran/use_device_addr-3.f90   -O3 -g  (test for excess errors)
    [-PASS:-]{+FAIL:+} libgomp.fortran/use_device_addr-3.f90   -O3 -g  execution test
    PASS: libgomp.fortran/use_device_addr-3.f90   -Os  (test for excess errors)
    PASS: libgomp.fortran/use_device_addr-3.f90   -Os  execution test
    
    libgomp: Trying to map into device [0x7ffd7915a500..0x7ffd7915a500) object when [0x7ffd7915c440..0x7ffd7915c440) is already mapped


    PASS: libgomp.fortran/use_device_addr-4.f90   -O0  (test for excess errors)
    PASS: libgomp.fortran/use_device_addr-4.f90   -O0  execution test
    PASS: libgomp.fortran/use_device_addr-4.f90   -O1  (test for excess errors)
    [-PASS:-]{+FAIL:+} libgomp.fortran/use_device_addr-4.f90   -O1  execution test
    PASS: libgomp.fortran/use_device_addr-4.f90   -O2  (test for excess errors)
    [-PASS:-]{+FAIL:+} libgomp.fortran/use_device_addr-4.f90   -O2  execution test
    PASS: libgomp.fortran/use_device_addr-4.f90   -O3 -fomit-frame-pointer -funroll-loops -fpeel-loops -ftracer -finline-functions  (test for excess errors)
    [-PASS:-]{+FAIL:+} libgomp.fortran/use_device_addr-4.f90   -O3 -fomit-frame-pointer -funroll-loops -fpeel-loops -ftracer -finline-functions  execution test
    PASS: libgomp.fortran/use_device_addr-4.f90   -O3 -g  (test for excess errors)
    [-PASS:-]{+FAIL:+} libgomp.fortran/use_device_addr-4.f90   -O3 -g  execution test
    PASS: libgomp.fortran/use_device_addr-4.f90   -Os  (test for excess errors)
    PASS: libgomp.fortran/use_device_addr-4.f90   -Os  execution test
    
    libgomp: Trying to map into device [0x7ffc70529ca0..0x7ffc70529ca0) object when [0x7ffc7052ac40..0x7ffc7052ac40) is already mapped


> Except for trivial changes to libgomp/oacc-mem.c

Just because something is just a few lines of code doesn't mean that it's
trivial.  I had asked you to first resolve that issue separately
(referencing PR92726), instead of mixing these changes into the Fortran
optional agruments commit:
<http://mid.mail-archive.com/87lfrylp8k.fsf@euler.schwinge.homeip.net>
"[PR92726] OpenACC: 'NULL'-in -> no-op, and/or 'NULL'-out".

There was no reason to rush in the Fortran optional arguments changes
before resolving the 'NULL' changes, was there?


> --- /dev/null
> +++ b/libgomp/testsuite/libgomp.oacc-fortran/optional-cache.f95
> @@ -0,0 +1,23 @@
> +! Test that the cache directives work with optional arguments.  [...]

Missing '{ dg-do run }'.


> --- /dev/null
> +++ b/libgomp/testsuite/libgomp.oacc-fortran/optional-cache.f95

> +! of giving a non-present argument to the cache directive is not tested as
> +! it is undefined.

> --- /dev/null
> +++ b/libgomp/testsuite/libgomp.oacc-fortran/optional-firstprivate.f90
> @@ -0,0 +1,112 @@
> +! Test that optional arguments work in firstprivate clauses.  The effect of
> +! non-present arguments in firstprivate clauses is undefined, and is not
> +! tested for.

> --- /dev/null
> +++ b/libgomp/testsuite/libgomp.oacc-fortran/optional-private.f90
> @@ -0,0 +1,115 @@
> +! Test that optional arguments work in private clauses.  The effect of
> +! non-present arguments in private clauses is undefined, and is not tested

> --- /dev/null
> +++ b/libgomp/testsuite/libgomp.oacc-fortran/optional-reduction.f90
> @@ -0,0 +1,69 @@
> +! Test optional arguments in reduction clauses.  The effect of
> +! non-present arguments in reduction clauses is undefined, and is not tested

Once you've got access, please file a ticket at
<https://github.com/OpenACC/openacc-spec/issues> so this gets clarified.


> --- /dev/null
> +++ b/libgomp/testsuite/libgomp.oacc-fortran/optional-reduction.f90

> +! { dg-additional-options "-w" }

Why that?


Grüße
 Thomas

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 658 bytes --]

^ permalink raw reply	[flat|nested] 65+ messages in thread

* [Patch, Fortran] OpenMP/OpenACC – fix more issues with OPTIONAL
@ 2019-12-10 17:54             ` Tobias Burnus
  2019-12-16  9:25               ` *ping* " Tobias Burnus
                                 ` (2 more replies)
  0 siblings, 3 replies; 65+ messages in thread
From: Tobias Burnus @ 2019-12-10 17:54 UTC (permalink / raw)
  To: gcc-patches, fortran, Jakub Jelinek, Thomas Schwinge

[-- Attachment #1: Type: text/plain, Size: 1615 bytes --]

Nonallocatable, nonpointer array arguments (of assumed shape) are 
special as they get a get an array descriptor ('arg') as argument but 
create a local variable which accesses the actual data ('arg.0 = 
arg->data').

With OPTIONAL, there are/were two outstanding issues:

(A) If the argument is not present, 'arg.0' is/was never assigned to.

(B) The optional-arg-is-present check is not just 'if (arg)' but 'if 
(arg && arg->data)' as passing an unallocated allocatable/disassociated 
pointer (i.e. 'arg->data = NULL') to a nonpointer, nonallocatable 
optional dummy argument counts as absent argument; this affects (A).

Solution:

(B) is now solved by updating what gfc_omp_check_optional_argument 
returns; as is now always returns an boolean_type_node, one can clean up 
the code which adds "!= NULL" when using the "present" tree variable.

(A) For mapping, one also does GOMP_MAP_POINTER; if one replaces this by 
a temporary variable 'D.124 = present ? arg.0 : NULL', it will later ICE 
in omp-low.c one confuses the identifier handling, which replaces the 
variables in 'target (data)'.

Build on x86-64-gnu-linux w/o offloading and on one nvptx configuration 
with actual offloading.
OK?

Tobias

PS: Besides adding tons of test cases, it also fixes the transient issue 
(which does only occur with -O1 ?!?) with the existing 
use_device_addr-{3,4}.f90 test case. That failed due to reason (A). – 
Cf. https://gcc.gnu.org/ml/gcc-patches/2019-12/msg00499.html

PPS: I haven't tried polymorphic data types but I am positive they will 
fail. Cray pointers are also candidates for additional failures.


[-- Attachment #2: extend-opt-mapping-v8.diff --]
[-- Type: text/x-patch, Size: 16037 bytes --]

2019-12-10  Tobias Burnus  <tobias@codesourcery.com>

	gcc/fortran/
	* trans-openmp.c (gfc_omp_check_optional_argument): Always return a
	Boolean expression; handle unallocated/disassociated actual arguments
	as absent if passed to nonallocatable/nonpointer dummy array arguments.
	(gfc_build_cond_assign): Change to assume a Boolean expr not a pointer.
	(gfc_omp_finish_clause, gfc_trans_omp_clauses): Assign NULL to generated
	array-data variable if the argument is absent. Simplify code as
	'present' is now a Boolean expression.

	libgomp/
	* testsuite/libgomp.fortran/optional-map.f90: Add test for
	unallocated/disassociated actual arguments to nonallocatable/nonpointer
	dummy arguments; those are/shall be regarded as absent arguments.
	* testsuite/libgomp.fortran/use_device_ptr-optional-2.f90: Ditto.
	* testsuite/libgomp.fortran/use_device_ptr-optional-3.f90: New.

 gcc/fortran/trans-openmp.c                         | 117 +++++++++++------
 libgomp/testsuite/libgomp.fortran/optional-map.f90 |  13 ++
 .../libgomp.fortran/use_device_ptr-optional-2.f90  |  11 ++
 .../libgomp.fortran/use_device_ptr-optional-3.f90  | 140 +++++++++++++++++++++
 4 files changed, 242 insertions(+), 39 deletions(-)

diff --git a/gcc/fortran/trans-openmp.c b/gcc/fortran/trans-openmp.c
index 356fd04e6c3..e46086d3916 100644
--- a/gcc/fortran/trans-openmp.c
+++ b/gcc/fortran/trans-openmp.c
@@ -90,11 +90,16 @@ gfc_omp_check_optional_argument (tree decl, bool for_present_check)
   if (!DECL_LANG_SPECIFIC (decl))
     return NULL_TREE;
 
+  bool is_array_type = false;
+
   /* For assumed-shape arrays, a local decl with arg->data is used.  */
   if (TREE_CODE (decl) != PARM_DECL
       && (GFC_DESCRIPTOR_TYPE_P (TREE_TYPE (decl))
 	  || GFC_ARRAY_TYPE_P (TREE_TYPE (decl))))
-    decl = GFC_DECL_SAVED_DESCRIPTOR (decl);
+    {
+      is_array_type = true;
+      decl = GFC_DECL_SAVED_DESCRIPTOR (decl);
+    }
 
   if (TREE_CODE (decl) != PARM_DECL
       || !DECL_LANG_SPECIFIC (decl)
@@ -126,7 +131,23 @@ gfc_omp_check_optional_argument (tree decl, bool for_present_check)
       return decl;
     }
 
-  return decl;
+  tree cond = fold_build2_loc (input_location, NE_EXPR, boolean_type_node,
+			       decl, null_pointer_node);
+
+  /* Fortran regards unallocated allocatables/disassociated pointer which
+     are passed to a nonallocatable, nonpointer argument as not associated;
+     cf. F2018, 15.5.2.12, Paragraph 1.  */
+  if (is_array_type)
+    {
+      tree cond2 = build_fold_indirect_ref_loc (input_location, decl);
+      cond2 = gfc_conv_array_data (cond2);
+      cond2 = fold_build2_loc (input_location, NE_EXPR, boolean_type_node,
+			       cond2, null_pointer_node);
+      cond = fold_build2_loc (input_location, TRUTH_ANDIF_EXPR,
+			      boolean_type_node, cond, cond2);
+    }
+
+  return cond;
 }
 
 
@@ -1189,7 +1210,7 @@ gfc_build_cond_assign (stmtblock_t *block, tree val, tree cond_val,
 		       tree then_b, tree else_val)
 {
   stmtblock_t cond_block;
-  tree cond, else_b = NULL_TREE;
+  tree else_b = NULL_TREE;
   tree val_ty = TREE_TYPE (val);
 
   if (else_val)
@@ -1198,15 +1219,9 @@ gfc_build_cond_assign (stmtblock_t *block, tree val, tree cond_val,
       gfc_add_modify (&cond_block, val, fold_convert (val_ty, else_val));
       else_b = gfc_finish_block (&cond_block);
     }
-  cond = fold_build2_loc (input_location, NE_EXPR,
-			  logical_type_node,
-			  cond_val, null_pointer_node);
   gfc_add_expr_to_block (block,
-			 build3_loc (input_location,
-				     COND_EXPR,
-				     void_type_node,
-				     cond, then_b,
-				     else_b));
+			 build3_loc (input_location, COND_EXPR, void_type_node,
+				     cond_val, then_b, else_b));
 }
 
 /* Build a conditional expression in BLOCK, returning a temporary
@@ -1257,8 +1272,7 @@ gfc_omp_finish_clause (tree c, gimple_seq *pre_p)
     }
 
   tree c2 = NULL_TREE, c3 = NULL_TREE, c4 = NULL_TREE;
-  tree present = (gfc_omp_is_optional_argument (decl)
-		  ? gfc_omp_check_optional_argument (decl, true) : NULL_TREE);
+  tree present = gfc_omp_check_optional_argument (decl, true);
   if (POINTER_TYPE_P (TREE_TYPE (decl)))
     {
       if (!gfc_omp_privatize_by_reference (decl)
@@ -1268,6 +1282,23 @@ gfc_omp_finish_clause (tree c, gimple_seq *pre_p)
 	  && !GFC_DESCRIPTOR_TYPE_P (TREE_TYPE (TREE_TYPE (decl))))
 	return;
       tree orig_decl = decl;
+
+      /* For nonallocatable, nonpointer arrays, a temporary variable is
+	 generated, but this one is only defined if the variable is present;
+	 hence, we now set it to NULL to avoid accessing undefined variables.
+	 We cannot use a temporary variable here as otherwise the replacement
+	 of the variables in omp-low.c will not work.  */
+      if (present && GFC_ARRAY_TYPE_P (TREE_TYPE (decl)))
+	{
+	  tree tmp = fold_build2_loc (input_location, MODIFY_EXPR,
+				      void_type_node, decl, null_pointer_node);
+	  tree cond = fold_build1_loc (input_location, TRUTH_NOT_EXPR,
+				       boolean_type_node, present);
+	  tmp = build3_loc (input_location, COND_EXPR, void_type_node,
+			    cond, tmp, NULL_TREE);
+	  gimplify_and_add (tmp, pre_p);
+	}
+
       c4 = build_omp_clause (OMP_CLAUSE_LOCATION (c), OMP_CLAUSE_MAP);
       OMP_CLAUSE_SET_MAP_KIND (c4, GOMP_MAP_POINTER);
       OMP_CLAUSE_DECL (c4) = decl;
@@ -1375,10 +1406,8 @@ gfc_omp_finish_clause (tree c, gimple_seq *pre_p)
 				  boolean_type_node, tem, null_pointer_node);
 	  if (present)
 	    {
-	      tem = fold_build2_loc (input_location, NE_EXPR, boolean_type_node,
-				     present, null_pointer_node);
 	      cond = fold_build2_loc (input_location, TRUTH_ANDIF_EXPR,
-				      boolean_type_node, tem, cond);
+				      boolean_type_node, present, cond);
 	    }
 	  gfc_add_expr_to_block (&block, build3_loc (input_location, COND_EXPR,
 						     void_type_node, cond,
@@ -2380,9 +2409,7 @@ gfc_trans_omp_clauses (stmtblock_t *block, gfc_omp_clauses *clauses,
 		TREE_ADDRESSABLE (decl) = 1;
 	      if (n->expr == NULL || n->expr->ref->u.ar.type == AR_FULL)
 		{
-		  tree present = (gfc_omp_is_optional_argument (decl)
-				  ? gfc_omp_check_optional_argument (decl, true)
-				  : NULL_TREE);
+		  tree present = gfc_omp_check_optional_argument (decl, true);
 		  if (POINTER_TYPE_P (TREE_TYPE (decl))
 		      && (gfc_omp_privatize_by_reference (decl)
 			  || GFC_DECL_GET_SCALAR_POINTER (decl)
@@ -2392,6 +2419,30 @@ gfc_trans_omp_clauses (stmtblock_t *block, gfc_omp_clauses *clauses,
 					(TREE_TYPE (TREE_TYPE (decl)))))
 		    {
 		      tree orig_decl = decl;
+
+		      /* For nonallocatable, nonpointer arrays, a temporary
+			 variable is generated, but this one is only defined if
+			 the variable is present; hence, we now set it to NULL
+			 to avoid accessing undefined variables.  We cannot use
+			 a temporary variable here as otherwise the replacement
+			 of the variables in omp-low.c will not work.  */
+		      if (present && GFC_ARRAY_TYPE_P (TREE_TYPE (decl)))
+			{
+			  tree tmp = fold_build2_loc (input_location,
+						      MODIFY_EXPR,
+						      void_type_node, decl,
+						      null_pointer_node);
+			  tree cond = fold_build1_loc (input_location,
+						       TRUTH_NOT_EXPR,
+						       boolean_type_node,
+						       present);
+			  gfc_add_expr_to_block (block,
+						 build3_loc (input_location,
+							     COND_EXPR,
+							     void_type_node,
+							     cond, tmp,
+							     NULL_TREE));
+			}
 		      node4 = build_omp_clause (input_location,
 						OMP_CLAUSE_MAP);
 		      OMP_CLAUSE_SET_MAP_KIND (node4, GOMP_MAP_POINTER);
@@ -2469,17 +2520,10 @@ gfc_trans_omp_clauses (stmtblock_t *block, gfc_omp_clauses *clauses,
 						  boolean_type_node,
 						  tem, null_pointer_node);
 			  if (present)
-			    {
-			      tree tmp = fold_build2_loc (input_location,
-							  NE_EXPR,
-							  boolean_type_node,
-							  present,
-							  null_pointer_node);
-			      cond = fold_build2_loc (input_location,
-						      TRUTH_ANDIF_EXPR,
-						      boolean_type_node,
-						      tmp, cond);
-			    }
+			    cond = fold_build2_loc (input_location,
+						    TRUTH_ANDIF_EXPR,
+						    boolean_type_node,
+						    present, cond);
 			  gfc_add_expr_to_block (block,
 						 build3_loc (input_location,
 							     COND_EXPR,
@@ -2498,16 +2542,11 @@ gfc_trans_omp_clauses (stmtblock_t *block, gfc_omp_clauses *clauses,
 			    {
 			      tree var = gfc_create_var (gfc_array_index_type,
 							 NULL);
-			      tree cond = fold_build2_loc (input_location,
-							   NE_EXPR,
-							   boolean_type_node,
-							   present,
-							   null_pointer_node);
 			      gfc_add_modify (&cond_block, var, size);
-			      cond = build3_loc (input_location, COND_EXPR,
-						 void_type_node, cond,
-						 gfc_finish_block (&cond_block),
-						 NULL_TREE);
+			      tree cond_body = gfc_finish_block (&cond_block);
+			      tree cond = build3_loc (input_location, COND_EXPR,
+						      void_type_node, present,
+						      cond_body, NULL_TREE);
 			      gfc_add_expr_to_block (block, cond);
 			      OMP_CLAUSE_SIZE (node) = var;
 			    }
diff --git a/libgomp/testsuite/libgomp.fortran/optional-map.f90 b/libgomp/testsuite/libgomp.fortran/optional-map.f90
index eebe58cc45c..b06efcc90d1 100644
--- a/libgomp/testsuite/libgomp.fortran/optional-map.f90
+++ b/libgomp/testsuite/libgomp.fortran/optional-map.f90
@@ -1,11 +1,24 @@
 ! { dg-do run }
 !
 implicit none (type, external)
+integer, allocatable :: a_ii, a_ival, a_iarr(:)
+integer, pointer :: p_ii, p_ival, p_iarr(:)
+
+nullify (p_ii, p_ival, p_iarr)
+
 call sub()
 call sub2()
 call call_present_1()
 call call_present_2()
 
+! unallocated/disassociated actual arguments to nonallocatable, nonpointer
+! dummy arguments are regarded as absent
+! Skipping 'ival' dummy argument due to PR fortran/92887
+call sub(ii=a_ii, iarr=a_iarr)
+call sub(ii=p_ii, iarr=p_iarr)
+call sub2(ii=a_ii, iarr=a_iarr)
+call sub2(ii=p_ii, iarr=p_iarr)
+
 contains
 
 subroutine call_present_1()
diff --git a/libgomp/testsuite/libgomp.fortran/use_device_ptr-optional-2.f90 b/libgomp/testsuite/libgomp.fortran/use_device_ptr-optional-2.f90
index d33b7d1cce0..641ebd98962 100644
--- a/libgomp/testsuite/libgomp.fortran/use_device_ptr-optional-2.f90
+++ b/libgomp/testsuite/libgomp.fortran/use_device_ptr-optional-2.f90
@@ -3,8 +3,19 @@
 program main
  use iso_c_binding, only: c_ptr, c_loc, c_associated
  implicit none (type, external)
+ integer, allocatable :: a_w, a_x(:)
+ integer, pointer :: p_w, p_x(:)
+
+ nullify (p_w, p_x)
  call foo()
+
+ ! unallocated/disassociated actual arguments to nonallocatable, nonpointer
+ ! dummy arguments are regarded as absent
+ call foo (w=a_w, x=a_x)
+ call foo (w=p_w, x=p_x)
+
 contains
+
   subroutine foo(v, w, x, y, z, cptr, cptr_in)
     integer, target, optional, value :: v
     integer, target, optional :: w
diff --git a/libgomp/testsuite/libgomp.fortran/use_device_ptr-optional-3.f90 b/libgomp/testsuite/libgomp.fortran/use_device_ptr-optional-3.f90
new file mode 100644
index 00000000000..f2e1a60757f
--- /dev/null
+++ b/libgomp/testsuite/libgomp.fortran/use_device_ptr-optional-3.f90
@@ -0,0 +1,140 @@
+! Check whether absent optional arguments are properly
+! handled with use_device_{addr,ptr}.
+program main
+  use iso_c_binding, only: c_ptr, c_loc, c_associated, c_f_pointer
+  implicit none (type, external)
+
+  integer, target :: u
+  integer, target :: v
+  integer, target :: w
+  integer, target :: x(4)
+  integer, target, allocatable :: y
+  integer, target, allocatable :: z(:)
+  type(c_ptr), target :: cptr
+  type(c_ptr), target :: cptr_in
+  integer :: dummy
+
+  u = 42
+  v = 5
+  w = 7
+  x = [3,4,6,2]
+  y = 88
+  z = [1,2,3]
+
+  !$omp target enter data map(to:u)
+  !$omp target data map(to:dummy) use_device_addr(u)
+   cptr_in = c_loc(u) ! Has to be outside 'foo' due to 'intent(in)'
+  !$omp end target data
+
+  call foo (u, v, w, x, y, z, cptr, cptr_in)
+  deallocate (y, z)
+contains
+  subroutine foo (u, v, w, x, y, z, cptr, cptr_in)
+    integer, target, optional, value :: v
+    integer, target, optional :: u, w
+    integer, target, optional :: x(:)
+    integer, target, optional, allocatable :: y
+    integer, target, optional, allocatable :: z(:)
+    type(c_ptr), target, optional, value :: cptr
+    type(c_ptr), target, optional, value, intent(in) :: cptr_in
+    integer :: d
+
+    type(c_ptr) :: p_u, p_v, p_w, p_x, p_y, p_z, p_cptr, p_cptr_in
+
+    !$omp target enter data map(to:w, x, y, z)
+    !$omp target data map(dummy) use_device_addr(x)
+      cptr = c_loc(x)
+    !$omp end target data
+
+    ! Need to map per-VALUE arguments, if present
+    if (present(v)) then
+      !$omp target enter data map(to:v)
+    else
+      stop 1
+    end if
+    if (present(cptr)) then
+      !$omp target enter data map(to:cptr)
+    else
+      stop 2
+    end if
+    if (present(cptr_in)) then
+      !$omp target enter data map(to:cptr_in)
+    else
+      stop 3
+    end if
+
+    !$omp target data map(d) use_device_addr(u, v, w, x, y, z)
+    !$omp target data map(d) use_device_addr(cptr, cptr_in)
+      if (.not. present(u)) stop 10
+      if (.not. present(v)) stop 11
+      if (.not. present(w)) stop 12
+      if (.not. present(x)) stop 13
+      if (.not. present(y)) stop 14
+      if (.not. present(z)) stop 15
+      if (.not. present(cptr)) stop 16
+      if (.not. present(cptr_in)) stop 17
+      p_u = c_loc(u)
+      p_v = c_loc(v)
+      p_w = c_loc(w)
+      p_x = c_loc(x)
+      p_y = c_loc(y)
+      p_z = c_loc(z)
+      p_cptr = c_loc(cptr)
+      p_cptr_in = c_loc(cptr_in)
+    !$omp end target data
+    !$omp end target data
+    call check(p_u, p_v, p_w, p_x, p_y, p_z, p_cptr, p_cptr_in, size(x), size(z))
+  end subroutine foo
+
+  subroutine check(p_u, p_v, p_w, p_x, p_y, p_z, p_cptr, p_cptr_in, Nx, Nz)
+    type(c_ptr), value :: p_u, p_v, p_w, p_x, p_y, p_z, p_cptr, p_cptr_in
+    integer, value :: Nx, Nz
+    integer, pointer :: c_u(:), c_v(:), c_w(:), c_x(:), c_y(:), c_z(:)
+    type(c_ptr), pointer :: c_cptr(:), c_cptr_in(:)
+
+    ! As is_device_ptr does not handle scalars, we map them to a size-1 array
+    call c_f_pointer(p_u, c_u, shape=[1])
+    call c_f_pointer(p_v, c_v, shape=[1])
+    call c_f_pointer(p_w, c_w, shape=[1])
+    call c_f_pointer(p_x, c_x, shape=[Nx])
+    call c_f_pointer(p_y, c_y, shape=[1])
+    call c_f_pointer(p_z, c_z, shape=[Nz])
+    call c_f_pointer(p_cptr, c_cptr, shape=[1])
+    call c_f_pointer(p_cptr_in, c_cptr_in, shape=[1])
+    call run_target(c_u, c_v, c_w, c_x, c_y, c_z, c_cptr, c_cptr_in, Nx, Nz)
+  end subroutine check
+
+  subroutine run_target(c_u, c_v, c_w, c_x, c_y, c_z, c_cptr, c_cptr_in, Nx, Nz)
+    integer, target :: c_u(:), c_v(:), c_w(:), c_x(:), c_y(:), c_z(:)
+    type(c_ptr) :: c_cptr(:), c_cptr_in(:)
+    integer, value :: Nx, Nz
+    !$omp target is_device_ptr(c_u, c_v, c_w, c_x, c_y, c_z, c_cptr, c_cptr_in) map(to:Nx, Nz)
+      call target_fn(c_u(1), c_v(1), c_w(1), c_x, c_y(1), c_z, c_cptr(1), c_cptr_in(1), Nx, Nz)
+    !$omp end target
+  end subroutine run_target
+
+  subroutine target_fn(c_u, c_v, c_w, c_x, c_y, c_z, c_cptr, c_cptr_in, Nx, Nz)
+    !$omp declare target
+    integer, target :: c_u, c_v, c_w, c_x(:), c_y, c_z(:)
+    type(c_ptr), value :: c_cptr, c_cptr_in
+    integer, value :: Nx, Nz
+    integer, pointer :: u, x(:)
+    if (c_u /= 42) stop 30
+    if (c_v /= 5) stop 31
+    if (c_w /= 7) stop 32
+    if (Nx /= 4) stop 33
+    if (any (c_x /= [3,4,6,2])) stop 34
+    if (c_y /= 88) stop 35
+    if (Nz /= 3) stop 36
+    if (any (c_z /= [1,2,3])) stop 37
+    if (.not. c_associated (c_cptr)) stop 38
+    if (.not. c_associated (c_cptr_in)) stop 39
+    if (.not. c_associated (c_cptr, c_loc(c_x))) stop 40
+    if (.not. c_associated (c_cptr_in, c_loc(c_u))) stop 41
+    call c_f_pointer(c_cptr_in, u)
+    call c_f_pointer(c_cptr, x, shape=[Nx])
+    if (u /= c_u .or. u /= 42)  stop 42
+    if (any (x /= c_x))  stop 43
+    if (any (x /= [3,4,6,2]))  stop 44
+  end subroutine target_fn
+end program main

^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: [Patch][OpenMP/OpenACC/Fortran] Fix mapping of optional (present|absent) arguments
  2019-12-07 14:49         ` [Patch][OpenMP/OpenACC/Fortran] Fix mapping of optional (present|absent) arguments Thomas Schwinge
@ 2019-12-11 10:52           ` Tobias Burnus
  2019-12-10 17:54             ` [Patch, Fortran] OpenMP/OpenACC – fix more issues with OPTIONAL Tobias Burnus
  0 siblings, 1 reply; 65+ messages in thread
From: Tobias Burnus @ 2019-12-11 10:52 UTC (permalink / raw)
  To: Thomas Schwinge; +Cc: gcc-patches, fortran, Jakub Jelinek

[-- Attachment #1: Type: text/plain, Size: 2405 bytes --]

Hi Thomas,

[Attached patch committed as Rev. 279217]
[One OpenMP (+OpenACC) patch and one OpenACC-only patch pending review 
are linked below.]

On 12/7/19 3:49 PM, Thomas Schwinge wrote:

> I'm seeing:
>      [-PASS:-]{+FAIL:+} libgomp.fortran/use_device_addr-3.f90   -O1  execution test

Whether it passed or not depended whether the stack was NULL for the 
local "array_arg.0" variable (which got assigned "array_arg->data" if 
the argument was present). Fixed by the following patch, which also 
fixes some more corner cases:

https://gcc.gnu.org/ml/gcc-patches/2019-12/msg00707.html – pending 
Jakub's review

>> Except for trivial changes to libgomp/oacc-mem.c
> Just because something is just a few lines of code doesn't mean that it's
> trivial.  I had asked you to first resolve that issue separately
> (referencing PR92726)

I vaguely remembered the this email – but couldn't find it in the 
thread. (This thread has 24 emails!)
Turned out that you wrote tht email in a different thread – and while 
this patch is mainly about Fortran, your email was also not set to 
fortran@ (arguably, your quoted text didn't include any Fortran bits).

Pending OpenACC review the thread you mentedion: 
https://gcc.gnu.org/ml/gcc-patches/2019-12/msg00062.html

>> --- /dev/null
>> +++ b/libgomp/testsuite/libgomp.oacc-fortran/optional-cache.f95
>> @@ -0,0 +1,23 @@
>> +! Test that the cache directives work with optional arguments.  [...]
> Missing '{ dg-do run }'.

Fixed/committed.

>> +! of giving a non-present argument to the cache directive is not tested as
>> +! it is undefined. […]
>> +! The effect of
>> +! non-present aguments in firstprivate clauses is undefined […] The effect of
>> +! non-present arguments in reduction clauses is undefined
> Once you've got access, please file a ticket at
> <https://github.com/OpenACC/openacc-spec/issues> so this gets clarified.

I will try to remember this – it's now on my to-do list.

>> +++ b/libgomp/testsuite/libgomp.oacc-fortran/optional-reduction.f90
>> +! { dg-additional-options "-w" }
> Why that?

No idea (was added by Kwok) – I do see warnings with "-Wall", but not 
with default options. (It then shows warnings like: "‘rg.25’ is used 
uninitialized in this function [-Wuninitialized]".)

I have now also removed this line → committed after testing that it runs 
through with nvptx.

Tobias


[-- Attachment #2: committed.diff --]
[-- Type: text/x-patch, Size: 2439 bytes --]

commit 6d8c93a07d3844bfcf646d3e53a8d57eb034c509
Author: burnus <burnus@138bc75d-0d04-0410-961f-82ee72b054a4>
Date:   Wed Dec 11 10:40:11 2019 +0000

    [OpenMP/OpenACC/Fortran] Fix mapping of optional (present|absent) arguments
    
            * testsuite/libgomp.oacc-fortran/optional-cache.f95: Add 'dg-do run'.
            * testsuite/libgomp.oacc-fortran/optional-reduction.f90: Remove
            unnecessary 'dg-additional-options "-w"'.
    
    
    
    git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@279217 138bc75d-0d04-0410-961f-82ee72b054a4

diff --git a/libgomp/ChangeLog b/libgomp/ChangeLog
index 83227032f88..14154088c95 100644
--- a/libgomp/ChangeLog
+++ b/libgomp/ChangeLog
@@ -1,3 +1,9 @@
+2019-12-11  Tobias Burnus  <tobias@codesourcery.com>
+
+	* testsuite/libgomp.oacc-fortran/optional-cache.f95: Add 'dg-do run'.
+	* testsuite/libgomp.oacc-fortran/optional-reduction.f90: Remove
+	unnecessary 'dg-additional-options "-w"'.
+
 2019-12-09  Thomas Schwinge  <thomas@codesourcery.com>
 	    Julian Brown  <julian@codesourcery.com>
 
@@ -11109,7 +11115,7 @@
 	PR libgomp/30546
 	* configure.ac: Add check for makeinfo
 	* Makefile.am: Redefined target libgomp.info, build libgomp.info only
-	if an appropiate version of makeinfo is found.
+	if an appropriate version of makeinfo is found.
 	* aclocal.m4: Regenerated.
 	* configure: Regenerated.
 	* Makefile.in: Regenerated.
diff --git a/libgomp/testsuite/libgomp.oacc-fortran/optional-cache.f95 b/libgomp/testsuite/libgomp.oacc-fortran/optional-cache.f95
index 00f7472ae6e..0d48e2bd786 100644
--- a/libgomp/testsuite/libgomp.oacc-fortran/optional-cache.f95
+++ b/libgomp/testsuite/libgomp.oacc-fortran/optional-cache.f95
@@ -1,3 +1,4 @@
+! { dg-do run }
 ! Test that the cache directives work with optional arguments.  The effect
 ! of giving a non-present argument to the cache directive is not tested as
 ! it is undefined.  The test is based on gfortran.dg/goacc/cache-1.f95.
diff --git a/libgomp/testsuite/libgomp.oacc-fortran/optional-reduction.f90 b/libgomp/testsuite/libgomp.oacc-fortran/optional-reduction.f90
index b76db3ef6d3..29f92c0d4c3 100644
--- a/libgomp/testsuite/libgomp.oacc-fortran/optional-reduction.f90
+++ b/libgomp/testsuite/libgomp.oacc-fortran/optional-reduction.f90
@@ -3,7 +3,6 @@
 ! for.  The tests are based on those in reduction-1.f90.
 
 ! { dg-do run }
-! { dg-additional-options "-w" }
 
 program optional_reduction
   implicit none

^ permalink raw reply	[flat|nested] 65+ messages in thread

* *ping* Re: [Patch, Fortran] OpenMP/OpenACC – fix more issues with OPTIONAL
  2019-12-10 17:54             ` [Patch, Fortran] OpenMP/OpenACC – fix more issues with OPTIONAL Tobias Burnus
@ 2019-12-16  9:25               ` Tobias Burnus
  2019-12-29 23:46                 ` *ping**2 " Tobias Burnus
  2020-01-03 11:29               ` Jakub Jelinek
  2020-01-08  8:33               ` Thomas Schwinge
  2 siblings, 1 reply; 65+ messages in thread
From: Tobias Burnus @ 2019-12-16  9:25 UTC (permalink / raw)
  To: gcc-patches, fortran, Jakub Jelinek, Thomas Schwinge

Ping.

On 12/10/19 6:54 PM, Tobias Burnus wrote:
> Nonallocatable, nonpointer array arguments (of assumed shape) are 
> special as they get a get an array descriptor ('arg') as argument but 
> create a local variable which accesses the actual data ('arg.0 = 
> arg->data').
>
> With OPTIONAL, there are/were two outstanding issues:
>
> (A) If the argument is not present, 'arg.0' is/was never assigned to.
>
> (B) The optional-arg-is-present check is not just 'if (arg)' but 'if 
> (arg && arg->data)' as passing an unallocated 
> allocatable/disassociated pointer (i.e. 'arg->data = NULL') to a 
> nonpointer, nonallocatable optional dummy argument counts as absent 
> argument; this affects (A).
>
> Solution: 

^ permalink raw reply	[flat|nested] 65+ messages in thread

* *ping**2 Re: [Patch, Fortran] OpenMP/OpenACC – fix more issues with OPTIONAL
  2019-12-16  9:25               ` *ping* " Tobias Burnus
@ 2019-12-29 23:46                 ` Tobias Burnus
  2019-12-30  4:33                   ` Jerry
  0 siblings, 1 reply; 65+ messages in thread
From: Tobias Burnus @ 2019-12-29 23:46 UTC (permalink / raw)
  To: gcc-patches, fortran, Jakub Jelinek, Thomas Schwinge; +Cc: Tobias Burnus


On 12/16/19 9:06 AM, Tobias Burnus wrote:
> Ping.
>
> On 12/10/19 6:54 PM, Tobias Burnus wrote:
>> Nonallocatable, nonpointer array arguments (of assumed shape) are 
>> special as they get a get an array descriptor ('arg') as argument but 
>> create a local variable which accesses the actual data ('arg.0 = 
>> arg->data').
>>
>> With OPTIONAL, there are/were two outstanding issues:
>>
>> (A) If the argument is not present, 'arg.0' is/was never assigned to.
>>
>> (B) The optional-arg-is-present check is not just 'if (arg)' but 'if 
>> (arg && arg->data)' as passing an unallocated 
>> allocatable/disassociated pointer (i.e. 'arg->data = NULL') to a 
>> nonpointer, nonallocatable optional dummy argument counts as absent 
>> argument; this affects (A).
>>
>> Solution: 

^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: *ping**2 Re: [Patch, Fortran] OpenMP/OpenACC – fix more issues with OPTIONAL
  2019-12-29 23:46                 ` *ping**2 " Tobias Burnus
@ 2019-12-30  4:33                   ` Jerry
  0 siblings, 0 replies; 65+ messages in thread
From: Jerry @ 2019-12-30  4:33 UTC (permalink / raw)
  To: Tobias Burnus, gcc-patches, fortran, Jakub Jelinek, Thomas Schwinge
  Cc: Tobias Burnus

Between Holidays and being short on people that understand this, I would 
say commit it unless Jakub objects.

(When in doubt, make a decision and move forward principle, assuming one 
is not stupid,)

Cheers,

Jerry

On 12/29/19 2:27 PM, Tobias Burnus wrote:
> 
> On 12/16/19 9:06 AM, Tobias Burnus wrote:
>> Ping.
>>
>> On 12/10/19 6:54 PM, Tobias Burnus wrote:
>>> Nonallocatable, nonpointer array arguments (of assumed shape) are 
>>> special as they get a get an array descriptor ('arg') as argument but 
>>> create a local variable which accesses the actual data ('arg.0 = 
>>> arg->data').
>>>
>>> With OPTIONAL, there are/were two outstanding issues:
>>>
>>> (A) If the argument is not present, 'arg.0' is/was never assigned to.
>>>
>>> (B) The optional-arg-is-present check is not just 'if (arg)' but 'if 
>>> (arg && arg->data)' as passing an unallocated 
>>> allocatable/disassociated pointer (i.e. 'arg->data = NULL') to a 
>>> nonpointer, nonallocatable optional dummy argument counts as absent 
>>> argument; this affects (A).
>>>
>>> Solution: 

^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: [Patch, Fortran] OpenMP/OpenACC – fix more issues with OPTIONAL
  2019-12-10 17:54             ` [Patch, Fortran] OpenMP/OpenACC – fix more issues with OPTIONAL Tobias Burnus
  2019-12-16  9:25               ` *ping* " Tobias Burnus
@ 2020-01-03 11:29               ` Jakub Jelinek
  2020-01-08  8:33               ` Thomas Schwinge
  2 siblings, 0 replies; 65+ messages in thread
From: Jakub Jelinek @ 2020-01-03 11:29 UTC (permalink / raw)
  To: Tobias Burnus; +Cc: gcc-patches, fortran, Thomas Schwinge

On Tue, Dec 10, 2019 at 06:54:19PM +0100, Tobias Burnus wrote:
> 2019-12-10  Tobias Burnus  <tobias@codesourcery.com>
> 
> 	gcc/fortran/
> 	* trans-openmp.c (gfc_omp_check_optional_argument): Always return a
> 	Boolean expression; handle unallocated/disassociated actual arguments
> 	as absent if passed to nonallocatable/nonpointer dummy array arguments.
> 	(gfc_build_cond_assign): Change to assume a Boolean expr not a pointer.
> 	(gfc_omp_finish_clause, gfc_trans_omp_clauses): Assign NULL to generated
> 	array-data variable if the argument is absent. Simplify code as
> 	'present' is now a Boolean expression.
> 
> 	libgomp/
> 	* testsuite/libgomp.fortran/optional-map.f90: Add test for
> 	unallocated/disassociated actual arguments to nonallocatable/nonpointer
> 	dummy arguments; those are/shall be regarded as absent arguments.
> 	* testsuite/libgomp.fortran/use_device_ptr-optional-2.f90: Ditto.
> 	* testsuite/libgomp.fortran/use_device_ptr-optional-3.f90: New.

Ok.  Sorry for the delay.

	Jakub

^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: [Patch, Fortran] OpenMP/OpenACC – fix more issues with OPTIONAL
  2019-12-10 17:54             ` [Patch, Fortran] OpenMP/OpenACC – fix more issues with OPTIONAL Tobias Burnus
  2019-12-16  9:25               ` *ping* " Tobias Burnus
  2020-01-03 11:29               ` Jakub Jelinek
@ 2020-01-08  8:33               ` Thomas Schwinge
  2020-01-08  8:55                 ` Tobias Burnus
  2 siblings, 1 reply; 65+ messages in thread
From: Thomas Schwinge @ 2020-01-08  8:33 UTC (permalink / raw)
  To: Tobias Burnus; +Cc: gcc-patches, fortran, Jakub Jelinek

[-- Attachment #1: Type: text/plain, Size: 9082 bytes --]

Hi Tobias!

On 2019-12-10T18:54:19+0100, Tobias Burnus <tobias@codesourcery.com> wrote:
> PS: Besides adding tons of test cases, [r279858] also fixes the transient issue 
> (which does only occur with -O1 ?!?)

(I saw it with different/differing optimization levels.)

> with the existing 
> use_device_addr-{3,4}.f90 test case. That failed due to [...]. – 
> Cf. https://gcc.gnu.org/ml/gcc-patches/2019-12/msg00499.html

ACK, thanks.


> PPS: I haven't tried polymorphic data types but I am positive they will 
> fail. Cray pointers are also candidates for additional failures.

Please file PRs as appropriate.


> 	* testsuite/libgomp.fortran/use_device_ptr-optional-3.f90: New.

With 'dg-do run' added, on powerpc64le-unknown-linux-gnu without
offloading I'm seeing:

    PASS: libgomp.fortran/use_device_ptr-optional-3.f90   -O0  (test for excess errors)
    FAIL: libgomp.fortran/use_device_ptr-optional-3.f90   -O0  execution test
    PASS: libgomp.fortran/use_device_ptr-optional-3.f90   -O1  (test for excess errors)
    PASS: libgomp.fortran/use_device_ptr-optional-3.f90   -O1  execution test
    PASS: libgomp.fortran/use_device_ptr-optional-3.f90   -O2  (test for excess errors)
    PASS: libgomp.fortran/use_device_ptr-optional-3.f90   -O2  execution test
    PASS: libgomp.fortran/use_device_ptr-optional-3.f90   -O3 -fomit-frame-pointer -funroll-loops -fpeel-loops -ftracer -finline-functions  (test for excess errors)
    PASS: libgomp.fortran/use_device_ptr-optional-3.f90   -O3 -fomit-frame-pointer -funroll-loops -fpeel-loops -ftracer -finline-functions  execution test
    PASS: libgomp.fortran/use_device_ptr-optional-3.f90   -O3 -g  (test for excess errors)
    PASS: libgomp.fortran/use_device_ptr-optional-3.f90   -O3 -g  execution test
    PASS: libgomp.fortran/use_device_ptr-optional-3.f90   -Os  (test for excess errors)
    PASS: libgomp.fortran/use_device_ptr-optional-3.f90   -Os  execution test

... with the '-O0' (only) execution test FAILing with 'STOP 1', and on
x86_64-pc-linux-gnu with offloading I'm seeing:

    PASS: libgomp.fortran/use_device_ptr-optional-3.f90   -O0  (test for excess errors)
    PASS: libgomp.fortran/use_device_ptr-optional-3.f90   -O0  execution test
    PASS: libgomp.fortran/use_device_ptr-optional-3.f90   -O1  (test for excess errors)
    PASS: libgomp.fortran/use_device_ptr-optional-3.f90   -O1  execution test
    FAIL: libgomp.fortran/use_device_ptr-optional-3.f90   -O2  (test for excess errors)
    UNRESOLVED: libgomp.fortran/use_device_ptr-optional-3.f90   -O2  compilation failed to produce executable
    FAIL: libgomp.fortran/use_device_ptr-optional-3.f90   -O3 -fomit-frame-pointer -funroll-loops -fpeel-loops -ftracer -finline-functions  (test for excess errors)
    UNRESOLVED: libgomp.fortran/use_device_ptr-optional-3.f90   -O3 -fomit-frame-pointer -funroll-loops -fpeel-loops -ftracer -finline-functions  compilation failed to produce executable
    FAIL: libgomp.fortran/use_device_ptr-optional-3.f90   -O3 -g  (test for excess errors)
    UNRESOLVED: libgomp.fortran/use_device_ptr-optional-3.f90   -O3 -g  compilation failed to produce executable
    FAIL: libgomp.fortran/use_device_ptr-optional-3.f90   -Os  (test for excess errors)
    UNRESOLVED: libgomp.fortran/use_device_ptr-optional-3.f90   -Os  compilation failed to produce executable

... due to:

    /tmp/cciVc43I.o:(.gnu.offload_vars+0x10): undefined reference to `A.12.4064'
    [...]

..., which may be something like PR90779, PR85063, PR84592, PR90779,
PR80411, PR71536 -- or something else.  ;-)


Grüße
 Thomas


> --- /dev/null
> +++ b/libgomp/testsuite/libgomp.fortran/use_device_ptr-optional-3.f90
> @@ -0,0 +1,140 @@
> +! Check whether absent optional arguments are properly
> +! handled with use_device_{addr,ptr}.
> +program main
> +  use iso_c_binding, only: c_ptr, c_loc, c_associated, c_f_pointer
> +  implicit none (type, external)
> +
> +  integer, target :: u
> +  integer, target :: v
> +  integer, target :: w
> +  integer, target :: x(4)
> +  integer, target, allocatable :: y
> +  integer, target, allocatable :: z(:)
> +  type(c_ptr), target :: cptr
> +  type(c_ptr), target :: cptr_in
> +  integer :: dummy
> +
> +  u = 42
> +  v = 5
> +  w = 7
> +  x = [3,4,6,2]
> +  y = 88
> +  z = [1,2,3]
> +
> +  !$omp target enter data map(to:u)
> +  !$omp target data map(to:dummy) use_device_addr(u)
> +   cptr_in = c_loc(u) ! Has to be outside 'foo' due to 'intent(in)'
> +  !$omp end target data
> +
> +  call foo (u, v, w, x, y, z, cptr, cptr_in)
> +  deallocate (y, z)
> +contains
> +  subroutine foo (u, v, w, x, y, z, cptr, cptr_in)
> +    integer, target, optional, value :: v
> +    integer, target, optional :: u, w
> +    integer, target, optional :: x(:)
> +    integer, target, optional, allocatable :: y
> +    integer, target, optional, allocatable :: z(:)
> +    type(c_ptr), target, optional, value :: cptr
> +    type(c_ptr), target, optional, value, intent(in) :: cptr_in
> +    integer :: d
> +
> +    type(c_ptr) :: p_u, p_v, p_w, p_x, p_y, p_z, p_cptr, p_cptr_in
> +
> +    !$omp target enter data map(to:w, x, y, z)
> +    !$omp target data map(dummy) use_device_addr(x)
> +      cptr = c_loc(x)
> +    !$omp end target data
> +
> +    ! Need to map per-VALUE arguments, if present
> +    if (present(v)) then
> +      !$omp target enter data map(to:v)
> +    else
> +      stop 1
> +    end if
> +    if (present(cptr)) then
> +      !$omp target enter data map(to:cptr)
> +    else
> +      stop 2
> +    end if
> +    if (present(cptr_in)) then
> +      !$omp target enter data map(to:cptr_in)
> +    else
> +      stop 3
> +    end if
> +
> +    !$omp target data map(d) use_device_addr(u, v, w, x, y, z)
> +    !$omp target data map(d) use_device_addr(cptr, cptr_in)
> +      if (.not. present(u)) stop 10
> +      if (.not. present(v)) stop 11
> +      if (.not. present(w)) stop 12
> +      if (.not. present(x)) stop 13
> +      if (.not. present(y)) stop 14
> +      if (.not. present(z)) stop 15
> +      if (.not. present(cptr)) stop 16
> +      if (.not. present(cptr_in)) stop 17
> +      p_u = c_loc(u)
> +      p_v = c_loc(v)
> +      p_w = c_loc(w)
> +      p_x = c_loc(x)
> +      p_y = c_loc(y)
> +      p_z = c_loc(z)
> +      p_cptr = c_loc(cptr)
> +      p_cptr_in = c_loc(cptr_in)
> +    !$omp end target data
> +    !$omp end target data
> +    call check(p_u, p_v, p_w, p_x, p_y, p_z, p_cptr, p_cptr_in, size(x), size(z))
> +  end subroutine foo
> +
> +  subroutine check(p_u, p_v, p_w, p_x, p_y, p_z, p_cptr, p_cptr_in, Nx, Nz)
> +    type(c_ptr), value :: p_u, p_v, p_w, p_x, p_y, p_z, p_cptr, p_cptr_in
> +    integer, value :: Nx, Nz
> +    integer, pointer :: c_u(:), c_v(:), c_w(:), c_x(:), c_y(:), c_z(:)
> +    type(c_ptr), pointer :: c_cptr(:), c_cptr_in(:)
> +
> +    ! As is_device_ptr does not handle scalars, we map them to a size-1 array
> +    call c_f_pointer(p_u, c_u, shape=[1])
> +    call c_f_pointer(p_v, c_v, shape=[1])
> +    call c_f_pointer(p_w, c_w, shape=[1])
> +    call c_f_pointer(p_x, c_x, shape=[Nx])
> +    call c_f_pointer(p_y, c_y, shape=[1])
> +    call c_f_pointer(p_z, c_z, shape=[Nz])
> +    call c_f_pointer(p_cptr, c_cptr, shape=[1])
> +    call c_f_pointer(p_cptr_in, c_cptr_in, shape=[1])
> +    call run_target(c_u, c_v, c_w, c_x, c_y, c_z, c_cptr, c_cptr_in, Nx, Nz)
> +  end subroutine check
> +
> +  subroutine run_target(c_u, c_v, c_w, c_x, c_y, c_z, c_cptr, c_cptr_in, Nx, Nz)
> +    integer, target :: c_u(:), c_v(:), c_w(:), c_x(:), c_y(:), c_z(:)
> +    type(c_ptr) :: c_cptr(:), c_cptr_in(:)
> +    integer, value :: Nx, Nz
> +    !$omp target is_device_ptr(c_u, c_v, c_w, c_x, c_y, c_z, c_cptr, c_cptr_in) map(to:Nx, Nz)
> +      call target_fn(c_u(1), c_v(1), c_w(1), c_x, c_y(1), c_z, c_cptr(1), c_cptr_in(1), Nx, Nz)
> +    !$omp end target
> +  end subroutine run_target
> +
> +  subroutine target_fn(c_u, c_v, c_w, c_x, c_y, c_z, c_cptr, c_cptr_in, Nx, Nz)
> +    !$omp declare target
> +    integer, target :: c_u, c_v, c_w, c_x(:), c_y, c_z(:)
> +    type(c_ptr), value :: c_cptr, c_cptr_in
> +    integer, value :: Nx, Nz
> +    integer, pointer :: u, x(:)
> +    if (c_u /= 42) stop 30
> +    if (c_v /= 5) stop 31
> +    if (c_w /= 7) stop 32
> +    if (Nx /= 4) stop 33
> +    if (any (c_x /= [3,4,6,2])) stop 34
> +    if (c_y /= 88) stop 35
> +    if (Nz /= 3) stop 36
> +    if (any (c_z /= [1,2,3])) stop 37
> +    if (.not. c_associated (c_cptr)) stop 38
> +    if (.not. c_associated (c_cptr_in)) stop 39
> +    if (.not. c_associated (c_cptr, c_loc(c_x))) stop 40
> +    if (.not. c_associated (c_cptr_in, c_loc(c_u))) stop 41
> +    call c_f_pointer(c_cptr_in, u)
> +    call c_f_pointer(c_cptr, x, shape=[Nx])
> +    if (u /= c_u .or. u /= 42)  stop 42
> +    if (any (x /= c_x))  stop 43
> +    if (any (x /= [3,4,6,2]))  stop 44
> +  end subroutine target_fn
> +end program main

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 658 bytes --]

^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: [Patch, Fortran] OpenMP/OpenACC – fix more issues with OPTIONAL
  2020-01-08  8:33               ` Thomas Schwinge
@ 2020-01-08  8:55                 ` Tobias Burnus
  2020-04-29 10:00                   ` Thomas Schwinge
  0 siblings, 1 reply; 65+ messages in thread
From: Tobias Burnus @ 2020-01-08  8:55 UTC (permalink / raw)
  To: Thomas Schwinge, Tobias Burnus; +Cc: gcc-patches, fortran, Jakub Jelinek

Hi Thomas,

On 1/8/20 9:33 AM, Thomas Schwinge wrote:
> With 'dg-do run' added, on powerpc64le-unknown-linux-gnu

Have I already expressed that I started to hate that target arch?

I think we really should find out what goes wrong for the small example 
of https://gcc.gnu.org/bugzilla/show_bug.cgi?id=92305 — Help and 
suggestions very much appreciated!

The reduced test case is in Comment 9 and Comment 11 shows the dump + 
the assembler of caller and callee. (The example is that short that 
pasting those in the comment still makes a rather short comment!) — 
Analysis is in later comments, especially in the last comment (Comment 16).

I think we should try to understand what goes wrong in this case before 
starting to look at other issues: it is already partially analyzed and 
it short. — Again, help and suggestions are welcome!

Hence, I am inclined to ignore the following issue — until we have 
understood and possibly fixed for PR92305.

> ... with the '-O0' (only) execution test FAILing with 'STOP 1'
While:
> x86_64-pc-linux-gnu with offloading I'm seeing:
>      FAIL: libgomp.fortran/use_device_ptr-optional-3.f90   -O2  (test for excess errors)
>      UNRESOLVED: libgomp.fortran/use_device_ptr-optional-3.f90   -O2  compilation failed to produce executable
> ... due to:
>      /tmp/cciVc43I.o:(.gnu.offload_vars+0x10): undefined reference to `A.12.4064'
> which may be something like PR90779, PR85063, PR84592, PR90779,
> PR80411, PR71536 -- or something else.

Hmm. It is surely among the listed items, if all fails in the last item. 
Note that PR85063 is fixed and PR84592 a duplicate of PR90779 (which is 
listed twice). To through in another number it could also be a variant 
of PR 92029 to though in yet another number …

Cheers,

Tobias

^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: [Patch, Fortran] OpenMP/OpenACC – fix more issues with OPTIONAL
  2020-01-08  8:55                 ` Tobias Burnus
@ 2020-04-29 10:00                   ` Thomas Schwinge
  2020-04-29 14:01                     ` Tobias Burnus
  0 siblings, 1 reply; 65+ messages in thread
From: Thomas Schwinge @ 2020-04-29 10:00 UTC (permalink / raw)
  To: Tobias Burnus; +Cc: gcc-patches, fortran, Jakub Jelinek

Hi Tobias!

Do you happen to have any update regarding this one:

On 2020-01-08T09:55:06+0100, Tobias Burnus <tobias@codesourcery.com> wrote:
> On 1/8/20 9:33 AM, Thomas Schwinge wrote:
>> With 'dg-do run' added, on [...] x86_64-pc-linux-gnu with offloading I'm seeing:

|     PASS: libgomp.fortran/use_device_ptr-optional-3.f90   -O0  (test for excess errors)
|     PASS: libgomp.fortran/use_device_ptr-optional-3.f90   -O0  execution test
|     PASS: libgomp.fortran/use_device_ptr-optional-3.f90   -O1  (test for excess errors)
|     PASS: libgomp.fortran/use_device_ptr-optional-3.f90   -O1  execution test
|     FAIL: libgomp.fortran/use_device_ptr-optional-3.f90   -O2  (test for excess errors)
|     UNRESOLVED: libgomp.fortran/use_device_ptr-optional-3.f90   -O2  compilation failed to produce executable
|     FAIL: libgomp.fortran/use_device_ptr-optional-3.f90   -O3 -fomit-frame-pointer -funroll-loops -fpeel-loops -ftracer -finline-functions  (test for excess errors)
|     UNRESOLVED: libgomp.fortran/use_device_ptr-optional-3.f90   -O3 -fomit-frame-pointer -funroll-loops -fpeel-loops -ftracer -finline-functions  compilation failed to produce executable
|     FAIL: libgomp.fortran/use_device_ptr-optional-3.f90   -O3 -g  (test for excess errors)
|     UNRESOLVED: libgomp.fortran/use_device_ptr-optional-3.f90   -O3 -g  compilation failed to produce executable
|     FAIL: libgomp.fortran/use_device_ptr-optional-3.f90   -Os  (test for excess errors)
|     UNRESOLVED: libgomp.fortran/use_device_ptr-optional-3.f90   -Os  compilation failed to produce executable

>> ... due to:
>>      /tmp/cciVc43I.o:(.gnu.offload_vars+0x10): undefined reference to `A.12.4064'
>> which may be something like PR90779, PR85063, PR84592, PR90779,
>> PR80411, PR71536 -- or something else.
>
> Hmm. It is surely among the listed items, if all fails in the last item.
> Note that PR85063 is fixed and PR84592 a duplicate of PR90779 (which is
> listed twice). To through in another number it could also be a variant
> of PR 92029 to though in yet another number …


Grüße
 Thomas
-----------------
Mentor Graphics (Deutschland) GmbH, Arnulfstraße 201, 80634 München / Germany
Registergericht München HRB 106955, Geschäftsführer: Thomas Heurung, Alexander Walter

^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: [Patch, Fortran] OpenMP/OpenACC – fix more issues with OPTIONAL
  2020-04-29 10:00                   ` Thomas Schwinge
@ 2020-04-29 14:01                     ` Tobias Burnus
  2020-04-30  6:24                       ` Richard Biener
  2020-06-17 22:22                       ` Thomas Schwinge
  0 siblings, 2 replies; 65+ messages in thread
From: Tobias Burnus @ 2020-04-29 14:01 UTC (permalink / raw)
  To: Thomas Schwinge; +Cc: Jakub Jelinek, gcc-patches, fortran

Hi Thomas,

was a bit on the backburner but I now digged again.
See: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=94848

The problem is a generated static array variable in the
device function:
   static integer(kind=4) A.12[3] = {1, 2, 3};
used as
   _26 = A.12[S.13_67];

With -ftree-pre, the expressions using _26 now directly use
the value (1, 2 and 3). It seems as if the variable A.12 is
eliminated before writing to LTO but the usage (A.12[S.…])
is not – at least it still appears in the device dumps.

Maybe it is also related to something else, but crucial is
the -ftree-pre on the host side; the optimization level on
the device lto1 side is irrelevant.

Cheers,

Tobias

On 4/29/20 12:00 PM, Thomas Schwinge wrote:

> Hi Tobias!
>
> Do you happen to have any update regarding this one:
>
> On 2020-01-08T09:55:06+0100, Tobias Burnus <tobias@codesourcery.com> wrote:
>> On 1/8/20 9:33 AM, Thomas Schwinge wrote:
>>> With 'dg-do run' added, on [...] x86_64-pc-linux-gnu with offloading I'm seeing:
> |     PASS: libgomp.fortran/use_device_ptr-optional-3.f90   -O0  (test for excess errors)
> |     PASS: libgomp.fortran/use_device_ptr-optional-3.f90   -O0  execution test
> |     PASS: libgomp.fortran/use_device_ptr-optional-3.f90   -O1  (test for excess errors)
> |     PASS: libgomp.fortran/use_device_ptr-optional-3.f90   -O1  execution test
> |     FAIL: libgomp.fortran/use_device_ptr-optional-3.f90   -O2  (test for excess errors)
> |     UNRESOLVED: libgomp.fortran/use_device_ptr-optional-3.f90   -O2  compilation failed to produce executable
> |     FAIL: libgomp.fortran/use_device_ptr-optional-3.f90   -O3 -fomit-frame-pointer -funroll-loops -fpeel-loops -ftracer -finline-functions  (test for excess errors)
> |     UNRESOLVED: libgomp.fortran/use_device_ptr-optional-3.f90   -O3 -fomit-frame-pointer -funroll-loops -fpeel-loops -ftracer -finline-functions  compilation failed to produce executable
> |     FAIL: libgomp.fortran/use_device_ptr-optional-3.f90   -O3 -g  (test for excess errors)
> |     UNRESOLVED: libgomp.fortran/use_device_ptr-optional-3.f90   -O3 -g  compilation failed to produce executable
> |     FAIL: libgomp.fortran/use_device_ptr-optional-3.f90   -Os  (test for excess errors)
> |     UNRESOLVED: libgomp.fortran/use_device_ptr-optional-3.f90   -Os  compilation failed to produce executable
>
>>> ... due to:
>>>       /tmp/cciVc43I.o:(.gnu.offload_vars+0x10): undefined reference to `A.12.4064'
>>> which may be something like PR90779, PR85063, PR84592, PR90779,
>>> PR80411, PR71536 -- or something else.
>> Hmm. It is surely among the listed items, if all fails in the last item.
>> Note that PR85063 is fixed and PR84592 a duplicate of PR90779 (which is
>> listed twice). To through in another number it could also be a variant
>> of PR 92029 to though in yet another number …
>
> Grüße
>   Thomas
> -----------------
> Mentor Graphics (Deutschland) GmbH, Arnulfstraße 201, 80634 München / Germany
> Registergericht München HRB 106955, Geschäftsführer: Thomas Heurung, Alexander Walter
-----------------
Mentor Graphics (Deutschland) GmbH, Arnulfstraße 201, 80634 München / Germany
Registergericht München HRB 106955, Geschäftsführer: Thomas Heurung, Alexander Walter

^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: [Patch, Fortran] OpenMP/OpenACC – fix more issues with OPTIONAL
  2020-04-29 14:01                     ` Tobias Burnus
@ 2020-04-30  6:24                       ` Richard Biener
  2020-04-30  7:17                         ` Jakub Jelinek
  2020-06-17 22:22                       ` Thomas Schwinge
  1 sibling, 1 reply; 65+ messages in thread
From: Richard Biener @ 2020-04-30  6:24 UTC (permalink / raw)
  To: Tobias Burnus; +Cc: Thomas Schwinge, Jakub Jelinek, GCC Patches, fortran

On Wed, Apr 29, 2020 at 5:05 PM Tobias Burnus <tobias@codesourcery.com> wrote:
>
> Hi Thomas,
>
> was a bit on the backburner but I now digged again.
> See: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=94848
>
> The problem is a generated static array variable in the
> device function:
>    static integer(kind=4) A.12[3] = {1, 2, 3};
> used as
>    _26 = A.12[S.13_67];
>
> With -ftree-pre, the expressions using _26 now directly use
> the value (1, 2 and 3). It seems as if the variable A.12 is
> eliminated before writing to LTO but the usage (A.12[S.…])
> is not – at least it still appears in the device dumps.
>
> Maybe it is also related to something else, but crucial is
> the -ftree-pre on the host side; the optimization level on
> the device lto1 side is irrelevant.

IIRC there was a bugreport similar to this where offload
variables were computed "early" instead of at the point
of streaming.

It's obvious that the offload "part" use is not reflected in
the non-offloat "part" IL (like via a function call parameter
or so), so I assume this is a local static in a function
we simply compile twice (but did not actually clone),
once for each offloat target and once for the host.  So it's
likely the above issue.

Richard.

> Cheers,
>
> Tobias
>
> On 4/29/20 12:00 PM, Thomas Schwinge wrote:
>
> > Hi Tobias!
> >
> > Do you happen to have any update regarding this one:
> >
> > On 2020-01-08T09:55:06+0100, Tobias Burnus <tobias@codesourcery.com> wrote:
> >> On 1/8/20 9:33 AM, Thomas Schwinge wrote:
> >>> With 'dg-do run' added, on [...] x86_64-pc-linux-gnu with offloading I'm seeing:
> > |     PASS: libgomp.fortran/use_device_ptr-optional-3.f90   -O0  (test for excess errors)
> > |     PASS: libgomp.fortran/use_device_ptr-optional-3.f90   -O0  execution test
> > |     PASS: libgomp.fortran/use_device_ptr-optional-3.f90   -O1  (test for excess errors)
> > |     PASS: libgomp.fortran/use_device_ptr-optional-3.f90   -O1  execution test
> > |     FAIL: libgomp.fortran/use_device_ptr-optional-3.f90   -O2  (test for excess errors)
> > |     UNRESOLVED: libgomp.fortran/use_device_ptr-optional-3.f90   -O2  compilation failed to produce executable
> > |     FAIL: libgomp.fortran/use_device_ptr-optional-3.f90   -O3 -fomit-frame-pointer -funroll-loops -fpeel-loops -ftracer -finline-functions  (test for excess errors)
> > |     UNRESOLVED: libgomp.fortran/use_device_ptr-optional-3.f90   -O3 -fomit-frame-pointer -funroll-loops -fpeel-loops -ftracer -finline-functions  compilation failed to produce executable
> > |     FAIL: libgomp.fortran/use_device_ptr-optional-3.f90   -O3 -g  (test for excess errors)
> > |     UNRESOLVED: libgomp.fortran/use_device_ptr-optional-3.f90   -O3 -g  compilation failed to produce executable
> > |     FAIL: libgomp.fortran/use_device_ptr-optional-3.f90   -Os  (test for excess errors)
> > |     UNRESOLVED: libgomp.fortran/use_device_ptr-optional-3.f90   -Os  compilation failed to produce executable
> >
> >>> ... due to:
> >>>       /tmp/cciVc43I.o:(.gnu.offload_vars+0x10): undefined reference to `A.12.4064'
> >>> which may be something like PR90779, PR85063, PR84592, PR90779,
> >>> PR80411, PR71536 -- or something else.
> >> Hmm. It is surely among the listed items, if all fails in the last item.
> >> Note that PR85063 is fixed and PR84592 a duplicate of PR90779 (which is
> >> listed twice). To through in another number it could also be a variant
> >> of PR 92029 to though in yet another number …
> >
> > Grüße
> >   Thomas
> > -----------------
> > Mentor Graphics (Deutschland) GmbH, Arnulfstraße 201, 80634 München / Germany
> > Registergericht München HRB 106955, Geschäftsführer: Thomas Heurung, Alexander Walter
> -----------------
> Mentor Graphics (Deutschland) GmbH, Arnulfstraße 201, 80634 München / Germany
> Registergericht München HRB 106955, Geschäftsführer: Thomas Heurung, Alexander Walter

^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: [Patch, Fortran] OpenMP/OpenACC – fix more issues with OPTIONAL
  2020-04-30  6:24                       ` Richard Biener
@ 2020-04-30  7:17                         ` Jakub Jelinek
  2020-05-05  9:08                           ` Tobias Burnus
  0 siblings, 1 reply; 65+ messages in thread
From: Jakub Jelinek @ 2020-04-30  7:17 UTC (permalink / raw)
  To: Richard Biener; +Cc: Tobias Burnus, Thomas Schwinge, GCC Patches, fortran

On Thu, Apr 30, 2020 at 08:24:02AM +0200, Richard Biener wrote:
> On Wed, Apr 29, 2020 at 5:05 PM Tobias Burnus <tobias@codesourcery.com> wrote:
> > was a bit on the backburner but I now digged again.
> > See: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=94848
> >
> > The problem is a generated static array variable in the
> > device function:
> >    static integer(kind=4) A.12[3] = {1, 2, 3};
> > used as
> >    _26 = A.12[S.13_67];
> >
> > With -ftree-pre, the expressions using _26 now directly use
> > the value (1, 2 and 3). It seems as if the variable A.12 is
> > eliminated before writing to LTO but the usage (A.12[S.…])
> > is not – at least it still appears in the device dumps.
> >
> > Maybe it is also related to something else, but crucial is
> > the -ftree-pre on the host side; the optimization level on
> > the device lto1 side is irrelevant.
> 
> IIRC there was a bugreport similar to this where offload
> variables were computed "early" instead of at the point
> of streaming.
> 
> It's obvious that the offload "part" use is not reflected in
> the non-offloat "part" IL (like via a function call parameter
> or so), so I assume this is a local static in a function
> we simply compile twice (but did not actually clone),
> once for each offloat target and once for the host.  So it's
> likely the above issue.

I'll try to do something about that early in stage1 and
eventually backport, we need to follow OpenMP rules anyway and
those require auto-discovery of referenced functions (if they are
definitions rather than just declarations), and similarly in
some cases for variables.  And the same code then could, if something
shouldn't be marked for offloading by the standard, complain loudly rather
than leaving it up for later (lto1 of the offloading compiler).

	Jakub


^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: [Patch, Fortran] OpenMP/OpenACC – fix more issues with OPTIONAL
  2020-04-30  7:17                         ` Jakub Jelinek
@ 2020-05-05  9:08                           ` Tobias Burnus
  0 siblings, 0 replies; 65+ messages in thread
From: Tobias Burnus @ 2020-05-05  9:08 UTC (permalink / raw)
  To: Jakub Jelinek, Richard Biener; +Cc: Thomas Schwinge, GCC Patches, fortran

On 4/30/20 9:17 AM, Jakub Jelinek wrote:

> I'll try to do something about that early in stage1 and
> eventually backport, we need to follow OpenMP rules anyway and
> those require auto-discovery of referenced functions (if they are
> definitions rather than just declarations), and similarly in
> some cases for variables.  And the same code then could, if something
> shouldn't be marked for offloading by the standard, complain loudly rather
> than leaving it up for later (lto1 of the offloading compiler).

Just as cross reference:

* PR 94320 – is about automatically marking functions as
   offloading; that's mostly relevant for C++ templates where
   using std::vector<> for instance might require that
   operator[] is marked for offloading.

* PR 94848 – is about the discussion in this thread, where
   a local static variable in a target function is partially
   optimized away. In principle, that could be solved by writing out
   the LTO stream consistently, i.e. either with the variable
   fully optimized away or being fully present (e.g. with
   "proper" function cloning).
   However, as done in other cases (see PR) – and alluded by
   Jakub above, is can also be solved by ensuring the variable
   is written out, i.e. by marking it for offloading.

Tobias

-----------------
Mentor Graphics (Deutschland) GmbH, Arnulfstraße 201, 80634 München / Germany
Registergericht München HRB 106955, Geschäftsführer: Thomas Heurung, Alexander Walter

^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: [Patch, Fortran] OpenMP/OpenACC – fix more issues with OPTIONAL
  2020-04-29 14:01                     ` Tobias Burnus
  2020-04-30  6:24                       ` Richard Biener
@ 2020-06-17 22:22                       ` Thomas Schwinge
  1 sibling, 0 replies; 65+ messages in thread
From: Thomas Schwinge @ 2020-06-17 22:22 UTC (permalink / raw)
  To: Tobias Burnus, gcc-patches; +Cc: Jakub Jelinek, fortran

[-- Attachment #1: Type: text/plain, Size: 2511 bytes --]

Hi!

On 2020-04-29T16:01:56+0200, Tobias Burnus <tobias@codesourcery.com> wrote:
> See: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=94848
>
> The problem is a generated static array variable in the
> device function:
>    static integer(kind=4) A.12[3] = {1, 2, 3};
> used as
>    _26 = A.12[S.13_67];
>
> [...]

..., and that PR was recently fixed, and so...

> On 4/29/20 12:00 PM, Thomas Schwinge wrote:
>> On 2020-01-08T09:55:06+0100, Tobias Burnus <tobias@codesourcery.com> wrote:
>>> On 1/8/20 9:33 AM, Thomas Schwinge wrote:
>>>> With 'dg-do run' added, on [...] x86_64-pc-linux-gnu with offloading I'm seeing:
>> |     PASS: libgomp.fortran/use_device_ptr-optional-3.f90   -O0  (test for excess errors)
>> |     PASS: libgomp.fortran/use_device_ptr-optional-3.f90   -O0  execution test
>> |     PASS: libgomp.fortran/use_device_ptr-optional-3.f90   -O1  (test for excess errors)
>> |     PASS: libgomp.fortran/use_device_ptr-optional-3.f90   -O1  execution test
>> |     FAIL: libgomp.fortran/use_device_ptr-optional-3.f90   -O2  (test for excess errors)
>> |     UNRESOLVED: libgomp.fortran/use_device_ptr-optional-3.f90   -O2  compilation failed to produce executable
>> |     FAIL: libgomp.fortran/use_device_ptr-optional-3.f90   -O3 -fomit-frame-pointer -funroll-loops -fpeel-loops -ftracer -finline-functions  (test for excess errors)
>> |     UNRESOLVED: libgomp.fortran/use_device_ptr-optional-3.f90   -O3 -fomit-frame-pointer -funroll-loops -fpeel-loops -ftracer -finline-functions  compilation failed to produce executable
>> |     FAIL: libgomp.fortran/use_device_ptr-optional-3.f90   -O3 -g  (test for excess errors)
>> |     UNRESOLVED: libgomp.fortran/use_device_ptr-optional-3.f90   -O3 -g  compilation failed to produce executable
>> |     FAIL: libgomp.fortran/use_device_ptr-optional-3.f90   -Os  (test for excess errors)
>> |     UNRESOLVED: libgomp.fortran/use_device_ptr-optional-3.f90   -Os  compilation failed to produce executable

... that problem now is gone, too.  I've thus pushed "Add 'dg-do run' to
'libgomp.fortran/use_device_ptr-optional-3.f90' [PR94848]" to master
branch in commit 5864930754f63e2dcef9606f2514ae20e80f436e, and
releases/gcc-10 branch in commit
61c896d84bdefbfffa7573a8af89119d4db7b3de, see attached.


Grüße
 Thomas


-----------------
Mentor Graphics (Deutschland) GmbH, Arnulfstraße 201, 80634 München / Germany
Registergericht München HRB 106955, Geschäftsführer: Thomas Heurung, Alexander Walter

[-- Attachment #2: 0001-Add-dg-do-run-to-libgomp.fortran-use_device_ptr-opti.patch --]
[-- Type: text/x-diff, Size: 2721 bytes --]

From 5864930754f63e2dcef9606f2514ae20e80f436e Mon Sep 17 00:00:00 2001
From: Thomas Schwinge <thomas@codesourcery.com>
Date: Tue, 7 Jan 2020 17:40:14 +0100
Subject: [PATCH] Add 'dg-do run' to
 'libgomp.fortran/use_device_ptr-optional-3.f90' [PR94848]
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Fix-up for r279858/commit f760c0c77fe350616da9dbeaea16442b0acfb09c "Fortran]
OpenMP/OpenACC – fix more issues with OPTIONAL".

With offloading enabled, we then saw:

    PASS: libgomp.fortran/use_device_ptr-optional-3.f90   -O0  (test for excess errors)
    PASS: libgomp.fortran/use_device_ptr-optional-3.f90   -O0  execution test
    PASS: libgomp.fortran/use_device_ptr-optional-3.f90   -O1  (test for excess errors)
    PASS: libgomp.fortran/use_device_ptr-optional-3.f90   -O1  execution test
    FAIL: libgomp.fortran/use_device_ptr-optional-3.f90   -O2  (test for excess errors)
    UNRESOLVED: libgomp.fortran/use_device_ptr-optional-3.f90   -O2  compilation failed to produce executable
    FAIL: libgomp.fortran/use_device_ptr-optional-3.f90   -O3 -fomit-frame-pointer -funroll-loops -fpeel-loops -ftracer -finline-functions  (test for excess errors)
    UNRESOLVED: libgomp.fortran/use_device_ptr-optional-3.f90   -O3 -fomit-frame-pointer -funroll-loops -fpeel-loops -ftracer -finline-functions  compilation failed to produce executable
    FAIL: libgomp.fortran/use_device_ptr-optional-3.f90   -O3 -g  (test for excess errors)
    UNRESOLVED: libgomp.fortran/use_device_ptr-optional-3.f90   -O3 -g  compilation failed to produce executable
    FAIL: libgomp.fortran/use_device_ptr-optional-3.f90   -Os  (test for excess errors)
    UNRESOLVED: libgomp.fortran/use_device_ptr-optional-3.f90   -Os  compilation failed to produce executable

 ... due to:

    /tmp/cciVc43I.o:(.gnu.offload_vars+0x10): undefined reference to `A.12.4064'
    [...]

..., but after the recent PR94848, PR95551 changes, that problem is now gone.

	libgomp/
	PR lto/94848
	* testsuite/libgomp.fortran/use_device_ptr-optional-3.f90: Add
	'dg-do run'.
---
 libgomp/testsuite/libgomp.fortran/use_device_ptr-optional-3.f90 | 1 +
 1 file changed, 1 insertion(+)

diff --git a/libgomp/testsuite/libgomp.fortran/use_device_ptr-optional-3.f90 b/libgomp/testsuite/libgomp.fortran/use_device_ptr-optional-3.f90
index f2e1a60757f9..b06a88415b47 100644
--- a/libgomp/testsuite/libgomp.fortran/use_device_ptr-optional-3.f90
+++ b/libgomp/testsuite/libgomp.fortran/use_device_ptr-optional-3.f90
@@ -1,3 +1,4 @@
+! { dg-do run }
 ! Check whether absent optional arguments are properly
 ! handled with use_device_{addr,ptr}.
 program main
-- 
2.27.0


[-- Attachment #3: 0001-Add-dg-do-run-to-libgomp.fortran-use_device_ptr-.g10.patch --]
[-- Type: text/x-diff, Size: 2793 bytes --]

From 61c896d84bdefbfffa7573a8af89119d4db7b3de Mon Sep 17 00:00:00 2001
From: Thomas Schwinge <thomas@codesourcery.com>
Date: Tue, 7 Jan 2020 17:40:14 +0100
Subject: [PATCH] Add 'dg-do run' to
 'libgomp.fortran/use_device_ptr-optional-3.f90' [PR94848]
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Fix-up for r279858/commit f760c0c77fe350616da9dbeaea16442b0acfb09c "Fortran]
OpenMP/OpenACC – fix more issues with OPTIONAL".

With offloading enabled, we then saw:

    PASS: libgomp.fortran/use_device_ptr-optional-3.f90   -O0  (test for excess errors)
    PASS: libgomp.fortran/use_device_ptr-optional-3.f90   -O0  execution test
    PASS: libgomp.fortran/use_device_ptr-optional-3.f90   -O1  (test for excess errors)
    PASS: libgomp.fortran/use_device_ptr-optional-3.f90   -O1  execution test
    FAIL: libgomp.fortran/use_device_ptr-optional-3.f90   -O2  (test for excess errors)
    UNRESOLVED: libgomp.fortran/use_device_ptr-optional-3.f90   -O2  compilation failed to produce executable
    FAIL: libgomp.fortran/use_device_ptr-optional-3.f90   -O3 -fomit-frame-pointer -funroll-loops -fpeel-loops -ftracer -finline-functions  (test for excess errors)
    UNRESOLVED: libgomp.fortran/use_device_ptr-optional-3.f90   -O3 -fomit-frame-pointer -funroll-loops -fpeel-loops -ftracer -finline-functions  compilation failed to produce executable
    FAIL: libgomp.fortran/use_device_ptr-optional-3.f90   -O3 -g  (test for excess errors)
    UNRESOLVED: libgomp.fortran/use_device_ptr-optional-3.f90   -O3 -g  compilation failed to produce executable
    FAIL: libgomp.fortran/use_device_ptr-optional-3.f90   -Os  (test for excess errors)
    UNRESOLVED: libgomp.fortran/use_device_ptr-optional-3.f90   -Os  compilation failed to produce executable

 ... due to:

    /tmp/cciVc43I.o:(.gnu.offload_vars+0x10): undefined reference to `A.12.4064'
    [...]

..., but after the recent PR94848, PR95551 changes, that problem is now gone.

	libgomp/
	PR lto/94848
	* testsuite/libgomp.fortran/use_device_ptr-optional-3.f90: Add
	'dg-do run'.

(cherry picked from commit 5864930754f63e2dcef9606f2514ae20e80f436e)
---
 libgomp/testsuite/libgomp.fortran/use_device_ptr-optional-3.f90 | 1 +
 1 file changed, 1 insertion(+)

diff --git a/libgomp/testsuite/libgomp.fortran/use_device_ptr-optional-3.f90 b/libgomp/testsuite/libgomp.fortran/use_device_ptr-optional-3.f90
index f2e1a60757f9..b06a88415b47 100644
--- a/libgomp/testsuite/libgomp.fortran/use_device_ptr-optional-3.f90
+++ b/libgomp/testsuite/libgomp.fortran/use_device_ptr-optional-3.f90
@@ -1,3 +1,4 @@
+! { dg-do run }
 ! Check whether absent optional arguments are properly
 ! handled with use_device_{addr,ptr}.
 program main
-- 
2.27.0


^ permalink raw reply	[flat|nested] 65+ messages in thread

end of thread, other threads:[~2020-06-17 22:22 UTC | newest]

Thread overview: 65+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
     [not found] <75222f0b-b55d-dcd9-b4f4-8e218675e8d7@mentor.com>
2019-07-12 11:35 ` [PATCH 0/5, OpenACC] Add support for Fortran optional arguments in OpenACC Kwok Cheung Yeung
2019-07-12 11:36   ` [PATCH 1/5, OpenACC] Allow NULL as an argument to OpenACC 2.6 directives Kwok Cheung Yeung
2019-11-29 14:42     ` [PR92726] OpenACC: 'NULL'-in -> no-op, and/or 'NULL'-out (was: [PATCH 1/5, OpenACC] Allow NULL as an argument to OpenACC 2.6 directives) Thomas Schwinge
2019-11-20 13:11       ` [Patch][OpenMP/OpenACC/Fortran] Fix mapping of optional (present|absent) arguments Tobias Burnus
2019-11-29 12:17         ` Tobias Burnus
2019-12-05 15:16         ` Jakub Jelinek
2019-12-05 15:47           ` [RFC] Characters per line: from punch card (80) to line printer (132) (was: [Patch][OpenMP/OpenACC/Fortran] Fix mapping of optional (present|absent) arguments) Thomas Schwinge
2019-12-05 16:04             ` Jakub Jelinek
2019-12-05 20:21               ` Segher Boessenkool
2019-12-05 16:17             ` Joseph Myers
2019-12-05 16:24               ` Paul Koning
2019-12-05 16:40                 ` Jeff Law
2019-12-05 16:55                 ` [RFC] Characters per line: from punch card (80) to line printer (132) Florian Weimer
2019-12-05 17:55               ` Andrew Stubbs
2019-12-05 18:12                 ` Eric Gallager
2019-12-05 18:22                 ` Robin Curtis
2019-12-05 19:16                   ` James Secan
2019-12-06  9:22                   ` Andrew Stubbs
2019-12-05 16:44             ` [RFC] Characters per line: from punch card (80) to line printer (132) (was: [Patch][OpenMP/OpenACC/Fortran] Fix mapping of optional (present|absent) arguments) Michael Matz
2019-12-05 17:03               ` Jonathan Wakely
2019-12-05 18:07                 ` Marek Polacek
2019-12-05 20:06                 ` Segher Boessenkool
2019-12-05 20:38                   ` Marek Polacek
2019-12-05 22:02                     ` Segher Boessenkool
2019-12-05 20:56                   ` Jonathan Wakely
2019-12-05 22:19                     ` Segher Boessenkool
2019-12-05 22:34                       ` Jonathan Wakely
2019-12-05 22:37                       ` Jonathan Wakely
2019-12-05 23:02                         ` Segher Boessenkool
2019-12-05 17:29               ` N.M. Maclaren
2019-12-05 20:12               ` Segher Boessenkool
2019-12-05 20:41               ` Jason Merrill
2019-12-05 18:54             ` [RFC] Characters per line: from punch card (80) to line printer (132) Martin Sebor
2019-12-05 20:32               ` Segher Boessenkool
2019-12-07 14:49         ` [Patch][OpenMP/OpenACC/Fortran] Fix mapping of optional (present|absent) arguments Thomas Schwinge
2019-12-11 10:52           ` Tobias Burnus
2019-12-10 17:54             ` [Patch, Fortran] OpenMP/OpenACC – fix more issues with OPTIONAL Tobias Burnus
2019-12-16  9:25               ` *ping* " Tobias Burnus
2019-12-29 23:46                 ` *ping**2 " Tobias Burnus
2019-12-30  4:33                   ` Jerry
2020-01-03 11:29               ` Jakub Jelinek
2020-01-08  8:33               ` Thomas Schwinge
2020-01-08  8:55                 ` Tobias Burnus
2020-04-29 10:00                   ` Thomas Schwinge
2020-04-29 14:01                     ` Tobias Burnus
2020-04-30  6:24                       ` Richard Biener
2020-04-30  7:17                         ` Jakub Jelinek
2020-05-05  9:08                           ` Tobias Burnus
2020-06-17 22:22                       ` Thomas Schwinge
2019-12-02 16:59       ` [PR92726] OpenACC: 'NULL'-in -> no-op, and/or 'NULL'-out Tobias Burnus
2019-07-12 11:37   ` [PATCH 2/5, OpenACC] Support Fortran optional arguments in the firstprivate clause Kwok Cheung Yeung
2019-07-12 11:42     ` Jakub Jelinek
2019-07-17 18:08       ` Kwok Cheung Yeung
2019-07-17 20:49         ` Tobias Burnus
2019-07-18  9:30           ` Tobias Burnus
2019-07-18 11:45             ` Kwok Cheung Yeung
2019-07-29 21:01       ` Kwok Cheung Yeung
2019-07-31 12:54         ` Jakub Jelinek
2019-10-07  9:26         ` Thomas Schwinge
2019-10-07 13:16           ` Kwok Cheung Yeung
2019-07-12 11:39   ` [PATCH 4/5, OpenACC] Allow optional arguments to be used in the use_device OpenACC clause Kwok Cheung Yeung
2019-07-29 22:42     ` Kwok Cheung Yeung
2019-07-31 13:13       ` Jakub Jelinek
2019-07-12 11:39   ` [PATCH 3/5, OpenACC] Add support for allocatable arrays as optional arguments Kwok Cheung Yeung
2019-07-12 11:41   ` [PATCH 5/5, OpenACC] Add tests for Fortran optional arguments in OpenACC 2.6 Kwok Cheung Yeung

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).