Fortran] OpenMP/OpenACC – fix more issues with OPTIONAL
authorTobias Burnus <tobias@codesourcery.com>
Fri, 3 Jan 2020 12:56:46 +0000 (12:56 +0000)
committerTobias Burnus <burnus@gcc.gnu.org>
Fri, 3 Jan 2020 12:56:46 +0000 (13:56 +0100)
        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.

From-SVN: r279858

gcc/fortran/ChangeLog
gcc/fortran/trans-openmp.c
libgomp/ChangeLog
libgomp/testsuite/libgomp.fortran/optional-map.f90
libgomp/testsuite/libgomp.fortran/use_device_ptr-optional-2.f90
libgomp/testsuite/libgomp.fortran/use_device_ptr-optional-3.f90 [new file with mode: 0644]

index 7f1bdc04be12d76613e59adc4b86d108ddad62b9..19397d6535376942cdcddd4176b112dccc21d1fb 100644 (file)
@@ -1,3 +1,13 @@
+2020-01-03  Tobias Burnus  <tobias@codesourcery.com>
+
+       * 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.
+
 2020-01-03  Tobias Burnus  <tobias@codesourcery.com>
 
        PR fortran/92994
index 553d4cb0891e2e3b40a3e7a9868062843e406d38..918af74bbf69dfbf33a9cd9e8fd4dfb2c7ce794b 100644 (file)
@@ -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;
 }
 
 
@@ -1192,7 +1213,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)
@@ -1201,15 +1222,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
@@ -1260,8 +1275,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)
@@ -1271,6 +1285,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;
@@ -1378,10 +1409,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,
@@ -2468,9 +2497,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 (n->sym->ts.type == BT_CLASS)
                    {
                      tree type = TREE_TYPE (decl);
@@ -2509,6 +2536,30 @@ gfc_trans_omp_clauses (stmtblock_t *block, gfc_omp_clauses *clauses,
                               || n->sym->ts.type == BT_DERIVED))
                    {
                      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);
@@ -2588,17 +2639,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,
@@ -2617,16 +2661,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;
                            }
index 4f9133125ac7dd5076498191651d58ed8c67bd0b..a204585d7b81f7136531641bd5ef3a9f0ae1bd1c 100644 (file)
@@ -1,3 +1,11 @@
+2020-01-03  Tobias Burnus  <tobias@codesourcery.com>
+
+       * 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.
+
 2020-01-01  Jakub Jelinek  <jakub@redhat.com>
 
        Update copyright years.
index eebe58cc45cd13ccc3d30fac6ce503d81d519618..b06efcc90d1042db6a0afe4559a95a89ca0428dd 100644 (file)
@@ -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()
index d33b7d1cce00dbe3f6419677d00ce04ca1b64830..641ebd98962a6daf621750efd449ab79ecb0efe7 100644 (file)
@@ -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 (file)
index 0000000..f2e1a60
--- /dev/null
@@ -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