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


Reply via email to