https://gcc.gnu.org/g:8bf0ee8d62b8a08e808344d31354ab713157e15d

commit r15-7643-g8bf0ee8d62b8a08e808344d31354ab713157e15d
Author: Andre Vehreschild <ve...@gcc.gnu.org>
Date:   Fri Feb 7 11:25:31 2025 +0100

    Fortran: Add transfer_between_remotes [PR107635]
    
    Add the last missing coarray data manipulation routine using remote
    accessors.
    
    gcc/fortran/ChangeLog:
    
            PR fortran/107635
    
            * coarray.cc (rewrite_caf_send): Rewrite to
            transfer_between_remotes when both sides of the assignment have
            a coarray.
            (coindexed_code_callback): Prevent duplicate rewrite.
            * gfortran.texi: Add documentation for transfer_between_remotes.
            * intrinsic.cc (add_subroutines): Add intrinsic symbol for
            caf_sendget to allow easy rewrite to transfer_between_remotes.
            * trans-decl.cc (gfc_build_builtin_function_decls): Add
            prototype for transfer_between_remotes.
            * trans-intrinsic.cc (conv_caf_vector_subscript_elem): Mark as
            deprecated.
            (conv_caf_vector_subscript): Same.
            (compute_component_offset): Same.
            (conv_expr_ref_to_caf_ref): Same.
            (conv_stat_and_team): Extract stat and team from expr.
            (gfc_conv_intrinsic_caf_get): Use conv_stat_and_team.
            (conv_caf_send_to_remote): Same.
            (has_ref_after_cafref): Mark as deprecated.
            (conv_caf_sendget): Translate to transfer_between_remotes.
            * trans.h: Add prototype for transfer_between_remotes.
    
    libgfortran/ChangeLog:
    
            * caf/libcaf.h: Add prototype for transfer_between_remotes.
            * caf/single.c: Implement transfer_between_remotes.
    
    gcc/testsuite/ChangeLog:
    
            * gfortran.dg/coarray_lib_comm_1.f90: Fix up scan_trees.

Diff:
---
 gcc/fortran/coarray.cc                           |   32 +-
 gcc/fortran/gfortran.texi                        |  106 +
 gcc/fortran/intrinsic.cc                         |    4 +
 gcc/fortran/trans-decl.cc                        |   15 +-
 gcc/fortran/trans-intrinsic.cc                   | 2346 ++++++++++++----------
 gcc/fortran/trans.h                              |    1 +
 gcc/testsuite/gfortran.dg/coarray_lib_comm_1.f90 |    4 +-
 libgfortran/caf/libcaf.h                         |   12 +
 libgfortran/caf/single.c                         |   69 +
 9 files changed, 1517 insertions(+), 1072 deletions(-)

diff --git a/gcc/fortran/coarray.cc b/gcc/fortran/coarray.cc
index 50029102eb9a..e5648e0d0279 100644
--- a/gcc/fortran/coarray.cc
+++ b/gcc/fortran/coarray.cc
@@ -1351,12 +1351,6 @@ rewrite_caf_send (gfc_code *c)
       && arg->next->next && arg->next->next->expr->expr_type == EXPR_VARIABLE)
     return;
 
-  if (gfc_is_coindexed (rhs))
-    {
-      c->resolved_isym->id = GFC_ISYM_CAF_SENDGET;
-      return;
-    }
-
   send_to_remote_expr = create_send_callback (lhs, rhs);
   send_to_remote_hash_expr = gfc_get_expr ();
   send_to_remote_hash_expr->expr_type = EXPR_CONSTANT;
@@ -1372,6 +1366,28 @@ rewrite_caf_send (gfc_code *c)
   arg = arg->next;
   arg->expr = send_to_remote_expr;
   gfc_add_caf_accessor (send_to_remote_hash_expr, send_to_remote_expr);
+
+  if (gfc_is_coindexed (rhs))
+    {
+      gfc_expr *get_from_remote_expr, *get_from_remote_hash_expr;
+
+      c->resolved_isym = gfc_intrinsic_subroutine_by_id (GFC_ISYM_CAF_SENDGET);
+      get_from_remote_expr = create_get_callback (rhs);
+      get_from_remote_hash_expr = gfc_get_expr ();
+      get_from_remote_hash_expr->expr_type = EXPR_CONSTANT;
+      get_from_remote_hash_expr->ts.type = BT_INTEGER;
+      get_from_remote_hash_expr->ts.kind = gfc_default_integer_kind;
+      get_from_remote_hash_expr->where = rhs->where;
+      mpz_init_set_ui (get_from_remote_hash_expr->value.integer,
+                      gfc_hash_value (get_from_remote_expr->symtree->n.sym));
+      arg->next = gfc_get_actual_arglist ();
+      arg = arg->next;
+      arg->expr = get_from_remote_hash_expr;
+      arg->next = gfc_get_actual_arglist ();
+      arg = arg->next;
+      arg->expr = get_from_remote_expr;
+      gfc_add_caf_accessor (get_from_remote_hash_expr, get_from_remote_expr);
+    }
 }
 
 static int
@@ -1451,7 +1467,9 @@ coindexed_code_callback (gfc_code **c, int *walk_subtrees,
            *walk_subtrees = 0;
            break;
          case GFC_ISYM_CAF_SENDGET:
-           // rewrite_caf_sendget (*c);
+           /* Seldomly this routine is called again with the symbol already
+              changed to CAF_SENDGET.  Do not process the subtree again.  The
+              rewrite has already been done by rewrite_caf_send ().  */
            *walk_subtrees = 0;
            break;
          case GFC_ISYM_ATOMIC_ADD:
diff --git a/gcc/fortran/gfortran.texi b/gcc/fortran/gfortran.texi
index 059022ea5439..36c203b27b3a 100644
--- a/gcc/fortran/gfortran.texi
+++ b/gcc/fortran/gfortran.texi
@@ -4214,6 +4214,7 @@ future implementation of teams.  It is about to change 
without further notice.
 * _gfortran_caf_get_from_remote:: Getting data from a remote image using a 
remote side accessor
 * _gfortran_caf_is_present_on_remote:: Check that a coarray or a part of it is 
allocated on the remote image
 * _gfortran_caf_send_to_remote:: Send data to a remote image using a remote 
side accessor to store it
+* _gfortran_caf_transfer_between_remotes:: Initiate data transfer between to 
remote images
 * _gfortran_caf_sendget_by_ref:: Sending data between remote images using 
enhanced references
 * _gfortran_caf_lock:: Locking a lock variable
 * _gfortran_caf_unlock:: Unlocking a lock variable
@@ -5153,6 +5154,111 @@ The implementation has to take care that it handles 
this case, e.g. using
 @end table
 
 
+@node _gfortran_caf_transfer_between_remotes
+@subsection @code{_gfortran_caf_transfer_between_remotes} --- Initiate data 
transfer between to remote images
+@cindex Coarray, _gfortran_caf_transfer_between_remotes
+
+@table @asis
+@item @emph{Description}:
+Initiates a transfer of data from one remote image to another remote image.
+The call modifies the memory of the receiving remote image given by
+@code{dst_image_index}.  The @code{src_image_index}'s memory is not modified.
+The call returns when the transfer has commenced.
+
+@item @emph{Syntax}:
+@code{void _gfortran_caf_transfer_between_remotes (caf_token_t dst_token,
+gfc_descriptor_t *opt_dst_desc, size_t *opt_dst_charlen,
+const int dst_image_index, const int dst_access_index, void *dst_add_data,
+const size_t dst_add_data_size, caf_token_t src_token,
+const gfc_descriptor_t *opt_src_desc, const size_t *opt_src_charlen,
+const int src_image_index, const int src_access_index, void *src_add_data,
+const size_t src_add_data_size, const size_t src_size,
+const bool scalar_transfer, int *dst_stat, int *src_stat, caf_team_t *dst_team,
+int *dst_team_number, caf_team_t *src_team, int *src_team_number)
+}
+
+@item @emph{Arguments}:
+@multitable @columnfractions .15 .70
+@item @var{dst_token} @tab intent(in)  An opaque pointer identifying the 
coarray
+on the receiving image.
+@item @var{opt_dst_desc} @tab intent(inout)  A pointer to the descriptor when
+the object identified by @var{dst_token} is an array with a descriptor.  The
+parameter needs to be set to @code{NULL}, when @var{dst_token} identifies a
+scalar or is an array without a descriptor.
+@item @var{opt_dst_charlen} @tab intent(in) When the object to modify on the
+receiving image is a char array with deferred length, then this parameter needs
+to be set to point to its length.  Else the parameter needs to be set to
+@code{NULL}.
+@item @var{dst_image_index} @tab intent(in)  The ID of the 
receiving/destination
+remote image; must be a positive number.  @code{this_image ()} is valid.
+@item @var{dst_access_index} @tab intent(in)  The index of the accessor to
+execute on the receiving image as returned by
+@code{_gfortran_caf_get_remote_function_index ()}.
+@item @var{dst_add_data} @tab intent(inout)  Additional data needed in the
+accessor on the receiving side.  I.e., when an array reference uses a local
+variable @var{v}, it is transported in this structure and all references in the
+accessor are rewritten to access the member.  The data in the structure of
+@var{dst_add_data} may be changed by the accessor, but these changes are lost 
to
+the calling Fortran program.
+@item @var{dst_add_data_size} @tab intent(in)  The size of the
+@var{dst_add_data} structure.
+@item @var{src_token} @tab intent(in)  An opaque pointer identifying the 
coarray
+on the sending image.
+@item @var{opt_src_desc} @tab intent(inout)  A pointer to the descriptor when
+the object identified by @var{src_token} is an array with a descriptor.  The
+parameter needs to be set to @code{NULL}, when @var{src_token} identifies a
+scalar or is an array without a descriptor.
+@item @var{opt_src_charlen} @tab intent(in) When the object to get from the
+source image is a char array with deferred length, then this parameter needs
+to be set to point to its length.  Else the parameter needs to be set to
+@code{NULL}.
+@item @var{src_image_index} @tab intent(in)  The ID of the sending/source
+remote image; must be a positive number.  @code{this_image ()} is valid.
+@item @var{src_access_index} @tab intent(in)  The index of the accessor to
+execute on the sending image as returned by
+@code{_gfortran_caf_get_remote_function_index ()}.
+@item @var{src_add_data} @tab intent(inout)  Additional data needed in the
+accessor on the sending side.  I.e., when an array reference uses a local
+variable @var{v}, it is transported in this structure and all references in the
+accessor are rewritten to access the member.  The data in the structure of
+@var{src_add_data} may be changed by the accessor, but these changes are lost 
to
+the calling Fortran program.
+@item @var{src_add_data_size} @tab intent(in)  The size of the
+@var{src_add_data} structure.
+@item @var{src_size} @tab intent(in) The size of data expected to be 
transferred
+between the images.  If the data type to get is a string or string array,
+then this needs to be set to the byte size of each character, i.e. @code{4} for
+a @code{CHARACTER (KIND=4)} string.  The length of the string is then given
+in @code{opt_src_charlen} and @code{opt_dst_charlen} (also for string arrays).
+@item @var{scalar_transfer} @tab intent(in)  Is set to true when the data to be
+transfered between the two images is not an array with a descriptor.
+@item @var{dst_stat} @tab intent(out) When non-@code{NULL} give the result of
+the operation on the receiving side, i.e., zero on success and non-zero on
+error.  When @code{NULL} and an error occurs, then an error message is printed
+and the program is terminated.
+@item @var{src_stat} @tab intent(out) When non-@code{NULL} give the result of
+the operation on the sending side, i.e., zero on success and non-zero on error.
+When @code{NULL} and an error occurs, then an error message is printed and the
+program is terminated.
+@item @var{dst_team} @tab intent(in)  The opaque team handle as returned by
+@code{FORM TEAM}.  Unused at the moment.
+@item @var{dst_team_number} @tab intent(in)  The number of the team this access
+is to be part of.  Unused at the moment.
+@item @var{src_team} @tab intent(in)  The opaque team handle as returned by
+@code{FORM TEAM}.  Unused at the moment.
+@item @var{src_team_number} @tab intent(in)  The number of the team this access
+is to be part of.  Unused at the moment.
+@end multitable
+
+@item @emph{NOTES}
+It is permitted to have both @code{dst_image_index} and @code{src_image_index}
+equal the current image; the memory to send the data to and the memory to read
+for the data may (partially) overlap.  The implementation has to take care that
+it handles this case, e.g. using @code{memmove} which handles (partially)
+overlapping memory.
+@end table
+
+
 @node _gfortran_caf_sendget_by_ref
 @subsection @code{_gfortran_caf_sendget_by_ref} --- Sending data between 
remote images using enhanced references on both sides
 @cindex Coarray, _gfortran_caf_sendget_by_ref
diff --git a/gcc/fortran/intrinsic.cc b/gcc/fortran/intrinsic.cc
index 99d5abcb9d5d..30f532b5766b 100644
--- a/gcc/fortran/intrinsic.cc
+++ b/gcc/fortran/intrinsic.cc
@@ -3898,6 +3898,10 @@ add_subroutines (void)
              "y", BT_REAL, dr, REQUIRED, INTENT_IN);
   make_from_module();
 
+  add_sym_2s (GFC_PREFIX ("caf_sendget"), GFC_ISYM_CAF_SENDGET, CLASS_IMPURE,
+             BT_UNKNOWN, 0, GFC_STD_GNU, NULL, NULL, NULL, "x", BT_REAL, dr,
+             REQUIRED, INTENT_OUT, "y", BT_REAL, dr, REQUIRED, INTENT_IN);
+  make_from_module ();
 
   /* More G77 compatibility garbage.  */
   add_sym_3s ("alarm", GFC_ISYM_ALARM, CLASS_IMPURE, BT_UNKNOWN, 0, 
GFC_STD_GNU,
diff --git a/gcc/fortran/trans-decl.cc b/gcc/fortran/trans-decl.cc
index 37df931075bb..025ad539d253 100644
--- a/gcc/fortran/trans-decl.cc
+++ b/gcc/fortran/trans-decl.cc
@@ -149,6 +149,7 @@ tree gfor_fndecl_caf_register_accessors_finish;
 tree gfor_fndecl_caf_get_remote_function_index;
 tree gfor_fndecl_caf_get_from_remote;
 tree gfor_fndecl_caf_send_to_remote;
+tree gfor_fndecl_caf_transfer_between_remotes;
 
 tree gfor_fndecl_caf_sync_all;
 tree gfor_fndecl_caf_sync_memory;
@@ -4144,9 +4145,19 @@ gfc_build_builtin_function_decls (void)
          pvoid_type_node, size_type_node, pint_type, pvoid_type_node,
          pint_type);
 
+      gfor_fndecl_caf_transfer_between_remotes
+       = gfc_build_library_function_decl_with_spec (
+         get_identifier (PREFIX ("caf_transfer_between_remotes")),
+         ". r r r r r r r r r r r r r r r r w w r r ", void_type_node, 20,
+         pvoid_type_node, pvoid_type_node, psize_type, integer_type_node,
+         integer_type_node, pvoid_type_node, size_type_node, pvoid_type_node,
+         pvoid_type_node, psize_type, integer_type_node, integer_type_node,
+         pvoid_type_node, size_type_node, size_type_node, boolean_type_node,
+         pint_type, pint_type, pvoid_type_node, pint_type);
+
       gfor_fndecl_caf_sync_all = gfc_build_library_function_decl_with_spec (
-       get_identifier (PREFIX("caf_sync_all")), ". w w . ", void_type_node,
-       3, pint_type, pchar_type_node, size_type_node);
+       get_identifier (PREFIX ("caf_sync_all")), ". w w . ", void_type_node, 3,
+       pint_type, pchar_type_node, size_type_node);
 
       gfor_fndecl_caf_sync_memory = gfc_build_library_function_decl_with_spec (
        get_identifier (PREFIX("caf_sync_memory")), ". w w . ", void_type_node,
diff --git a/gcc/fortran/trans-intrinsic.cc b/gcc/fortran/trans-intrinsic.cc
index 19286f7a0ae0..84f18a533a92 100644
--- a/gcc/fortran/trans-intrinsic.cc
+++ b/gcc/fortran/trans-intrinsic.cc
@@ -1041,632 +1041,636 @@ gfc_conv_intrinsic_exponent (gfc_se *se, gfc_expr 
*expr)
        } u;
      }  */
 
-static void
-conv_caf_vector_subscript_elem (stmtblock_t *block, int i, tree desc,
-                               tree lower, tree upper, tree stride,
-                               tree vector, int kind, tree nvec)
-{
-  tree field, type, tmp;
-
-  desc = gfc_build_array_ref (desc, gfc_rank_cst[i], NULL_TREE);
-  type = TREE_TYPE (desc);
-
-  field = gfc_advance_chain (TYPE_FIELDS (type), 0);
-  tmp = fold_build3_loc (input_location, COMPONENT_REF, TREE_TYPE (field),
-                        desc, field, NULL_TREE);
-  gfc_add_modify (block, tmp, fold_convert (TREE_TYPE (field), nvec));
-
-  /* Access union.  */
-  field = gfc_advance_chain (TYPE_FIELDS (type), 1);
-  desc = fold_build3_loc (input_location, COMPONENT_REF, TREE_TYPE (field),
-                         desc, field, NULL_TREE);
-  type = TREE_TYPE (desc);
-
-  /* Access the inner struct.  */
-  field = gfc_advance_chain (TYPE_FIELDS (type), vector != NULL_TREE ? 0 : 1);
-  desc = fold_build3_loc (input_location, COMPONENT_REF, TREE_TYPE (field),
-                     desc, field, NULL_TREE);
-  type = TREE_TYPE (desc);
-
-  if (vector != NULL_TREE)
-    {
-      /* Set vector and kind.  */
-      field = gfc_advance_chain (TYPE_FIELDS (type), 0);
-      tmp = fold_build3_loc (input_location, COMPONENT_REF, TREE_TYPE (field),
-                        desc, field, NULL_TREE);
-      gfc_add_modify (block, tmp, fold_convert (TREE_TYPE (field), vector));
-      field = gfc_advance_chain (TYPE_FIELDS (type), 1);
-      tmp = fold_build3_loc (input_location, COMPONENT_REF, TREE_TYPE (field),
-                        desc, field, NULL_TREE);
-      gfc_add_modify (block, tmp, build_int_cst (integer_type_node, kind));
-    }
-  else
-    {
-      /* Set dim.lower/upper/stride.  */
-      field = gfc_advance_chain (TYPE_FIELDS (type), 0);
-      tmp = fold_build3_loc (input_location, COMPONENT_REF, TREE_TYPE (field),
-                            desc, field, NULL_TREE);
-      gfc_add_modify (block, tmp, fold_convert (TREE_TYPE (field), lower));
-
-      field = gfc_advance_chain (TYPE_FIELDS (type), 1);
-      tmp = fold_build3_loc (input_location, COMPONENT_REF, TREE_TYPE (field),
-                            desc, field, NULL_TREE);
-      gfc_add_modify (block, tmp, fold_convert (TREE_TYPE (field), upper));
-
-      field = gfc_advance_chain (TYPE_FIELDS (type), 2);
-      tmp = fold_build3_loc (input_location, COMPONENT_REF, TREE_TYPE (field),
-                            desc, field, NULL_TREE);
-      gfc_add_modify (block, tmp, fold_convert (TREE_TYPE (field), stride));
-    }
-}
-
-
-static tree
-conv_caf_vector_subscript (stmtblock_t *block, tree desc, gfc_array_ref *ar)
-{
-  gfc_se argse;
-  tree var, lower, upper = NULL_TREE, stride = NULL_TREE, vector, nvec;
-  tree lbound, ubound, tmp;
-  int i;
-
-  var = gfc_create_var (gfc_get_caf_vector_type (ar->dimen), "vector");
-
-  for (i = 0; i < ar->dimen; i++)
-    switch (ar->dimen_type[i])
-      {
-      case DIMEN_RANGE:
-        if (ar->end[i])
-         {
-           gfc_init_se (&argse, NULL);
-           gfc_conv_expr (&argse, ar->end[i]);
-           gfc_add_block_to_block (block, &argse.pre);
-           upper = gfc_evaluate_now (argse.expr, block);
-         }
-        else
-         upper = gfc_conv_descriptor_ubound_get (desc, gfc_rank_cst[i]);
-       if (ar->stride[i])
-         {
-           gfc_init_se (&argse, NULL);
-           gfc_conv_expr (&argse, ar->stride[i]);
-           gfc_add_block_to_block (block, &argse.pre);
-           stride = gfc_evaluate_now (argse.expr, block);
-         }
-       else
-         stride = gfc_index_one_node;
-
-       /* Fall through.  */
-      case DIMEN_ELEMENT:
-       if (ar->start[i])
-         {
-           gfc_init_se (&argse, NULL);
-           gfc_conv_expr (&argse, ar->start[i]);
-           gfc_add_block_to_block (block, &argse.pre);
-           lower = gfc_evaluate_now (argse.expr, block);
-         }
-       else
-         lower = gfc_conv_descriptor_lbound_get (desc, gfc_rank_cst[i]);
-       if (ar->dimen_type[i] == DIMEN_ELEMENT)
-         {
-           upper = lower;
-           stride = gfc_index_one_node;
-         }
-       vector = NULL_TREE;
-       nvec = size_zero_node;
-       conv_caf_vector_subscript_elem (block, i, var, lower, upper, stride,
-                                       vector, 0, nvec);
-       break;
-
-      case DIMEN_VECTOR:
-       gfc_init_se (&argse, NULL);
-       argse.descriptor_only = 1;
-       gfc_conv_expr_descriptor (&argse, ar->start[i]);
-       gfc_add_block_to_block (block, &argse.pre);
-       vector = argse.expr;
-       lbound = gfc_conv_descriptor_lbound_get (vector, gfc_rank_cst[0]);
-       ubound = gfc_conv_descriptor_ubound_get (vector, gfc_rank_cst[0]);
-       nvec = gfc_conv_array_extent_dim (lbound, ubound, NULL);
-        tmp = gfc_conv_descriptor_stride_get (vector, gfc_rank_cst[0]);
-       nvec = fold_build2_loc (input_location, TRUNC_DIV_EXPR,
-                               TREE_TYPE (nvec), nvec, tmp);
-       lower = gfc_index_zero_node;
-       upper = gfc_index_zero_node;
-       stride = gfc_index_zero_node;
-       vector = gfc_conv_descriptor_data_get (vector);
-       conv_caf_vector_subscript_elem (block, i, var, lower, upper, stride,
-                                       vector, ar->start[i]->ts.kind, nvec);
-       break;
-      default:
-       gcc_unreachable();
-    }
-  return gfc_build_addr_expr (NULL_TREE, var);
-}
-
-
-static tree
-compute_component_offset (tree field, tree type)
-{
-  tree tmp;
-  if (DECL_FIELD_BIT_OFFSET (field) != NULL_TREE
-      && !integer_zerop (DECL_FIELD_BIT_OFFSET (field)))
-    {
-      tmp = fold_build2 (TRUNC_DIV_EXPR, type,
-                        DECL_FIELD_BIT_OFFSET (field),
-                        bitsize_unit_node);
-      return fold_build2 (PLUS_EXPR, type, DECL_FIELD_OFFSET (field), tmp);
-    }
-  else
-    return DECL_FIELD_OFFSET (field);
-}
-
-
-static tree
-conv_expr_ref_to_caf_ref (stmtblock_t *block, gfc_expr *expr)
-{
-  gfc_ref *ref = expr->ref, *last_comp_ref;
-  tree caf_ref = NULL_TREE, prev_caf_ref = NULL_TREE, reference_type, tmp, 
tmp2,
-      field, last_type, inner_struct, mode, mode_rhs, dim_array, dim, dim_type,
-      start, end, stride, vector, nvec;
-  gfc_se se;
-  bool ref_static_array = false;
-  tree last_component_ref_tree = NULL_TREE;
-  int i, last_type_n;
-
-  if (expr->symtree)
-    {
-      last_component_ref_tree = expr->symtree->n.sym->backend_decl;
-      ref_static_array = !expr->symtree->n.sym->attr.allocatable
-         && !expr->symtree->n.sym->attr.pointer;
-    }
-
-  /* Prevent uninit-warning.  */
-  reference_type = NULL_TREE;
-
-  /* Skip refs upto the first coarray-ref.  */
-  last_comp_ref = NULL;
-  while (ref && (ref->type != REF_ARRAY || ref->u.ar.codimen == 0))
-    {
-      /* Remember the type of components skipped.  */
-      if (ref->type == REF_COMPONENT)
-       last_comp_ref = ref;
-      ref = ref->next;
-    }
-  /* When a component was skipped, get the type information of the last
-     component ref, else get the type from the symbol.  */
-  if (last_comp_ref)
-    {
-      last_type = gfc_typenode_for_spec (&last_comp_ref->u.c.component->ts);
-      last_type_n = last_comp_ref->u.c.component->ts.type;
-    }
-  else
-    {
-      last_type = gfc_typenode_for_spec (&expr->symtree->n.sym->ts);
-      last_type_n = expr->symtree->n.sym->ts.type;
-    }
-
-  while (ref)
-    {
-      if (ref->type == REF_ARRAY && ref->u.ar.codimen > 0
-         && ref->u.ar.dimen == 0)
-       {
-         /* Skip pure coindexes.  */
-         ref = ref->next;
-         continue;
-       }
-      tmp = gfc_create_var (gfc_get_caf_reference_type (), "caf_ref");
-      reference_type = TREE_TYPE (tmp);
-
-      if (caf_ref == NULL_TREE)
-       caf_ref = tmp;
-
-      /* Construct the chain of refs.  */
-      if (prev_caf_ref != NULL_TREE)
-       {
-         field = gfc_advance_chain (TYPE_FIELDS (reference_type), 0);
-         tmp2 = fold_build3_loc (input_location, COMPONENT_REF,
-                                 TREE_TYPE (field), prev_caf_ref, field,
-                                 NULL_TREE);
-         gfc_add_modify (block, tmp2, gfc_build_addr_expr (TREE_TYPE (field),
-                                                           tmp));
-       }
-      prev_caf_ref = tmp;
-
-      switch (ref->type)
-       {
-       case REF_COMPONENT:
-         last_type = gfc_typenode_for_spec (&ref->u.c.component->ts);
-         last_type_n = ref->u.c.component->ts.type;
-         /* Set the type of the ref.  */
-         field = gfc_advance_chain (TYPE_FIELDS (reference_type), 1);
-         tmp = fold_build3_loc (input_location, COMPONENT_REF,
-                                TREE_TYPE (field), prev_caf_ref, field,
-                                NULL_TREE);
-         gfc_add_modify (block, tmp, build_int_cst (integer_type_node,
-                                                    GFC_CAF_REF_COMPONENT));
-
-         /* Ref the c in union u.  */
-         field = gfc_advance_chain (TYPE_FIELDS (reference_type), 3);
-         tmp = fold_build3_loc (input_location, COMPONENT_REF,
-                                TREE_TYPE (field), prev_caf_ref, field,
-                                NULL_TREE);
-         field = gfc_advance_chain (TYPE_FIELDS (TREE_TYPE (field)), 0);
-         inner_struct = fold_build3_loc (input_location, COMPONENT_REF,
-                                      TREE_TYPE (field), tmp, field,
-                                      NULL_TREE);
-
-         /* Set the offset.  */
-         field = gfc_advance_chain (TYPE_FIELDS (TREE_TYPE (inner_struct)), 0);
-         tmp = fold_build3_loc (input_location, COMPONENT_REF,
-                                TREE_TYPE (field), inner_struct, field,
-                                NULL_TREE);
-         /* Computing the offset is somewhat harder.  The bit_offset has to be
-            taken into account.  When the bit_offset in the field_decl is non-
-            null, divide it by the bitsize_unit and add it to the regular
-            offset.  */
-         tmp2 = compute_component_offset (ref->u.c.component->backend_decl,
-                                          TREE_TYPE (tmp));
-         gfc_add_modify (block, tmp, fold_convert (TREE_TYPE (tmp), tmp2));
-
-         /* Set caf_token_offset.  */
-         field = gfc_advance_chain (TYPE_FIELDS (TREE_TYPE (inner_struct)), 1);
-         tmp = fold_build3_loc (input_location, COMPONENT_REF,
-                                TREE_TYPE (field), inner_struct, field,
-                                NULL_TREE);
-         if ((ref->u.c.component->attr.allocatable
-              || ref->u.c.component->attr.pointer)
-             && ref->u.c.component->attr.dimension)
-           {
-             tree arr_desc_token_offset;
-             /* Get the token field from the descriptor.  */
-             arr_desc_token_offset = TREE_OPERAND (
-                   gfc_conv_descriptor_token 
(ref->u.c.component->backend_decl), 1);
-             arr_desc_token_offset
-                 = compute_component_offset (arr_desc_token_offset,
-                                             TREE_TYPE (tmp));
-             tmp2 = fold_build2_loc (input_location, PLUS_EXPR,
-                                     TREE_TYPE (tmp2), tmp2,
-                                     arr_desc_token_offset);
-           }
-         else if (ref->u.c.component->caf_token)
-           tmp2 = compute_component_offset (gfc_comp_caf_token (
-                                              ref->u.c.component),
-                                            TREE_TYPE (tmp));
-         else
-           tmp2 = integer_zero_node;
-         gfc_add_modify (block, tmp, fold_convert (TREE_TYPE (tmp), tmp2));
-
-         /* Remember whether this ref was to a non-allocatable/non-pointer
-            component so the next array ref can be tailored correctly.  */
-         ref_static_array = !ref->u.c.component->attr.allocatable
-             && !ref->u.c.component->attr.pointer;
-         last_component_ref_tree = ref_static_array
-             ? ref->u.c.component->backend_decl : NULL_TREE;
-         break;
-       case REF_ARRAY:
-         if (ref_static_array && ref->u.ar.as->type == AS_DEFERRED)
-           ref_static_array = false;
-         /* Set the type of the ref.  */
-         field = gfc_advance_chain (TYPE_FIELDS (reference_type), 1);
-         tmp = fold_build3_loc (input_location, COMPONENT_REF,
-                                TREE_TYPE (field), prev_caf_ref, field,
-                                NULL_TREE);
-         gfc_add_modify (block, tmp, build_int_cst (integer_type_node,
-                                                    ref_static_array
-                                                    ? GFC_CAF_REF_STATIC_ARRAY
-                                                    : GFC_CAF_REF_ARRAY));
-
-         /* Ref the a in union u.  */
-         field = gfc_advance_chain (TYPE_FIELDS (reference_type), 3);
-         tmp = fold_build3_loc (input_location, COMPONENT_REF,
-                                TREE_TYPE (field), prev_caf_ref, field,
-                                NULL_TREE);
-         field = gfc_advance_chain (TYPE_FIELDS (TREE_TYPE (field)), 1);
-         inner_struct = fold_build3_loc (input_location, COMPONENT_REF,
-                                      TREE_TYPE (field), tmp, field,
-                                      NULL_TREE);
-
-         /* Set the static_array_type in a for static arrays.  */
-         if (ref_static_array)
-           {
-             field = gfc_advance_chain (TYPE_FIELDS (TREE_TYPE (inner_struct)),
-                                        1);
-             tmp = fold_build3_loc (input_location, COMPONENT_REF,
-                                    TREE_TYPE (field), inner_struct, field,
-                                    NULL_TREE);
-             gfc_add_modify (block, tmp, build_int_cst (TREE_TYPE (tmp),
-                                                        last_type_n));
-           }
-         /* Ref the mode in the inner_struct.  */
-         field = gfc_advance_chain (TYPE_FIELDS (TREE_TYPE (inner_struct)), 0);
-         mode = fold_build3_loc (input_location, COMPONENT_REF,
-                                 TREE_TYPE (field), inner_struct, field,
-                                 NULL_TREE);
-         /* Ref the dim in the inner_struct.  */
-         field = gfc_advance_chain (TYPE_FIELDS (TREE_TYPE (inner_struct)), 2);
-         dim_array = fold_build3_loc (input_location, COMPONENT_REF,
-                                      TREE_TYPE (field), inner_struct, field,
-                                      NULL_TREE);
-         for (i = 0; i < ref->u.ar.dimen; ++i)
-           {
-             /* Ref dim i.  */
-             dim = gfc_build_array_ref (dim_array, gfc_rank_cst[i], NULL_TREE);
-             dim_type = TREE_TYPE (dim);
-             mode_rhs = start = end = stride = NULL_TREE;
-             switch (ref->u.ar.dimen_type[i])
-               {
-               case DIMEN_RANGE:
-                 if (ref->u.ar.end[i])
-                   {
-                     gfc_init_se (&se, NULL);
-                     gfc_conv_expr (&se, ref->u.ar.end[i]);
-                     gfc_add_block_to_block (block, &se.pre);
-                     if (ref_static_array)
-                       {
-                         /* Make the index zero-based, when reffing a static
-                            array.  */
-                         end = se.expr;
-                         gfc_init_se (&se, NULL);
-                         gfc_conv_expr (&se, ref->u.ar.as->lower[i]);
-                         gfc_add_block_to_block (block, &se.pre);
-                         se.expr = fold_build2 (MINUS_EXPR,
-                                                gfc_array_index_type,
-                                                end, fold_convert (
-                                                  gfc_array_index_type,
-                                                  se.expr));
-                       }
-                     end = gfc_evaluate_now (fold_convert (
-                                               gfc_array_index_type,
-                                               se.expr),
-                                             block);
-                   }
-                 else if (ref_static_array)
-                   end = fold_build2 (MINUS_EXPR,
-                                      gfc_array_index_type,
-                                      gfc_conv_array_ubound (
-                                        last_component_ref_tree, i),
-                                      gfc_conv_array_lbound (
-                                        last_component_ref_tree, i));
-                 else
-                   {
-                     end = NULL_TREE;
-                     mode_rhs = build_int_cst (unsigned_char_type_node,
-                                               GFC_CAF_ARR_REF_OPEN_END);
-                   }
-                 if (ref->u.ar.stride[i])
-                   {
-                     gfc_init_se (&se, NULL);
-                     gfc_conv_expr (&se, ref->u.ar.stride[i]);
-                     gfc_add_block_to_block (block, &se.pre);
-                     stride = gfc_evaluate_now (fold_convert (
-                                                  gfc_array_index_type,
-                                                  se.expr),
-                                                block);
-                     if (ref_static_array)
-                       {
-                         /* Make the index zero-based, when reffing a static
-                            array.  */
-                         stride = fold_build2 (MULT_EXPR,
-                                               gfc_array_index_type,
-                                               gfc_conv_array_stride (
-                                                 last_component_ref_tree,
-                                                 i),
-                                               stride);
-                         gcc_assert (end != NULL_TREE);
-                         /* Multiply with the product of array's stride and
-                            the step of the ref to a virtual upper bound.
-                            We cannot compute the actual upper bound here or
-                            the caflib would compute the extend
-                            incorrectly.  */
-                         end = fold_build2 (MULT_EXPR, gfc_array_index_type,
-                                            end, gfc_conv_array_stride (
-                                              last_component_ref_tree,
-                                              i));
-                         end = gfc_evaluate_now (end, block);
-                         stride = gfc_evaluate_now (stride, block);
-                       }
-                   }
-                 else if (ref_static_array)
-                   {
-                     stride = gfc_conv_array_stride (last_component_ref_tree,
-                                                     i);
-                     end = fold_build2 (MULT_EXPR, gfc_array_index_type,
-                                        end, stride);
-                     end = gfc_evaluate_now (end, block);
-                   }
-                 else
-                   /* Always set a ref stride of one to make caflib's
-                      handling easier.  */
-                   stride = gfc_index_one_node;
-
-                 /* Fall through.  */
-               case DIMEN_ELEMENT:
-                 if (ref->u.ar.start[i])
-                   {
-                     gfc_init_se (&se, NULL);
-                     gfc_conv_expr (&se, ref->u.ar.start[i]);
-                     gfc_add_block_to_block (block, &se.pre);
-                     if (ref_static_array)
-                       {
-                         /* Make the index zero-based, when reffing a static
-                            array.  */
-                         start = fold_convert (gfc_array_index_type, se.expr);
-                         gfc_init_se (&se, NULL);
-                         gfc_conv_expr (&se, ref->u.ar.as->lower[i]);
-                         gfc_add_block_to_block (block, &se.pre);
-                         se.expr = fold_build2 (MINUS_EXPR,
-                                                gfc_array_index_type,
-                                                start, fold_convert (
-                                                  gfc_array_index_type,
-                                                  se.expr));
-                         /* Multiply with the stride.  */
-                         se.expr = fold_build2 (MULT_EXPR,
-                                                gfc_array_index_type,
-                                                se.expr,
-                                                gfc_conv_array_stride (
-                                                  last_component_ref_tree,
-                                                  i));
-                       }
-                     start = gfc_evaluate_now (fold_convert (
-                                                 gfc_array_index_type,
-                                                 se.expr),
-                                               block);
-                     if (mode_rhs == NULL_TREE)
-                       mode_rhs = build_int_cst (unsigned_char_type_node,
-                                                 ref->u.ar.dimen_type[i]
-                                                 == DIMEN_ELEMENT
-                                                 ? GFC_CAF_ARR_REF_SINGLE
-                                                 : GFC_CAF_ARR_REF_RANGE);
-                   }
-                 else if (ref_static_array)
-                   {
-                     start = integer_zero_node;
-                     mode_rhs = build_int_cst (unsigned_char_type_node,
-                                               ref->u.ar.start[i] == NULL
-                                               ? GFC_CAF_ARR_REF_FULL
-                                               : GFC_CAF_ARR_REF_RANGE);
-                   }
-                 else if (end == NULL_TREE)
-                   mode_rhs = build_int_cst (unsigned_char_type_node,
-                                             GFC_CAF_ARR_REF_FULL);
-                 else
-                   mode_rhs = build_int_cst (unsigned_char_type_node,
-                                             GFC_CAF_ARR_REF_OPEN_START);
-
-                 /* Ref the s in dim.  */
-                 field = gfc_advance_chain (TYPE_FIELDS (dim_type), 0);
-                 tmp = fold_build3_loc (input_location, COMPONENT_REF,
-                                        TREE_TYPE (field), dim, field,
-                                        NULL_TREE);
-
-                 /* Set start in s.  */
-                 if (start != NULL_TREE)
-                   {
-                     field = gfc_advance_chain (TYPE_FIELDS (TREE_TYPE (tmp)),
-                                                0);
-                     tmp2 = fold_build3_loc (input_location, COMPONENT_REF,
-                                             TREE_TYPE (field), tmp, field,
-                                             NULL_TREE);
-                     gfc_add_modify (block, tmp2,
-                                     fold_convert (TREE_TYPE (tmp2), start));
-                   }
-
-                 /* Set end in s.  */
-                 if (end != NULL_TREE)
-                   {
-                     field = gfc_advance_chain (TYPE_FIELDS (TREE_TYPE (tmp)),
-                                                1);
-                     tmp2 = fold_build3_loc (input_location, COMPONENT_REF,
-                                             TREE_TYPE (field), tmp, field,
-                                             NULL_TREE);
-                     gfc_add_modify (block, tmp2,
-                                     fold_convert (TREE_TYPE (tmp2), end));
-                   }
-
-                 /* Set end in s.  */
-                 if (stride != NULL_TREE)
-                   {
-                     field = gfc_advance_chain (TYPE_FIELDS (TREE_TYPE (tmp)),
-                                                2);
-                     tmp2 = fold_build3_loc (input_location, COMPONENT_REF,
-                                             TREE_TYPE (field), tmp, field,
-                                             NULL_TREE);
-                     gfc_add_modify (block, tmp2,
-                                     fold_convert (TREE_TYPE (tmp2), stride));
-                   }
-                 break;
-               case DIMEN_VECTOR:
-                 /* TODO: In case of static array.  */
-                 gcc_assert (!ref_static_array);
-                 mode_rhs = build_int_cst (unsigned_char_type_node,
-                                           GFC_CAF_ARR_REF_VECTOR);
-                 gfc_init_se (&se, NULL);
-                 se.descriptor_only = 1;
-                 gfc_conv_expr_descriptor (&se, ref->u.ar.start[i]);
-                 gfc_add_block_to_block (block, &se.pre);
-                 vector = se.expr;
-                 tmp = gfc_conv_descriptor_lbound_get (vector,
-                                                       gfc_rank_cst[0]);
-                 tmp2 = gfc_conv_descriptor_ubound_get (vector,
-                                                        gfc_rank_cst[0]);
-                 nvec = gfc_conv_array_extent_dim (tmp, tmp2, NULL);
-                 tmp = gfc_conv_descriptor_stride_get (vector,
-                                                       gfc_rank_cst[0]);
-                 nvec = fold_build2_loc (input_location, TRUNC_DIV_EXPR,
-                                         TREE_TYPE (nvec), nvec, tmp);
-                 vector = gfc_conv_descriptor_data_get (vector);
-
-                 /* Ref the v in dim.  */
-                 field = gfc_advance_chain (TYPE_FIELDS (dim_type), 1);
-                 tmp = fold_build3_loc (input_location, COMPONENT_REF,
-                                        TREE_TYPE (field), dim, field,
-                                        NULL_TREE);
-
-                 /* Set vector in v.  */
-                 field = gfc_advance_chain (TYPE_FIELDS (TREE_TYPE (tmp)), 0);
-                 tmp2 = fold_build3_loc (input_location, COMPONENT_REF,
-                                         TREE_TYPE (field), tmp, field,
-                                         NULL_TREE);
-                 gfc_add_modify (block, tmp2, fold_convert (TREE_TYPE (tmp2),
-                                                            vector));
-
-                 /* Set nvec in v.  */
-                 field = gfc_advance_chain (TYPE_FIELDS (TREE_TYPE (tmp)), 1);
-                 tmp2 = fold_build3_loc (input_location, COMPONENT_REF,
-                                         TREE_TYPE (field), tmp, field,
-                                         NULL_TREE);
-                 gfc_add_modify (block, tmp2, fold_convert (TREE_TYPE (tmp2),
-                                                            nvec));
-
-                 /* Set kind in v.  */
-                 field = gfc_advance_chain (TYPE_FIELDS (TREE_TYPE (tmp)), 2);
-                 tmp2 = fold_build3_loc (input_location, COMPONENT_REF,
-                                         TREE_TYPE (field), tmp, field,
-                                         NULL_TREE);
-                 gfc_add_modify (block, tmp2, build_int_cst (integer_type_node,
-                                                 ref->u.ar.start[i]->ts.kind));
-                 break;
-               default:
-                 gcc_unreachable ();
-               }
-             /* Set the mode for dim i.  */
-             tmp = gfc_build_array_ref (mode, gfc_rank_cst[i], NULL_TREE);
-             gfc_add_modify (block, tmp, fold_convert (TREE_TYPE (tmp),
-                                                       mode_rhs));
-           }
-
-         /* Set the mode for dim i+1 to GFC_ARR_REF_NONE.  */
-         if (i < GFC_MAX_DIMENSIONS)
-           {
-             tmp = gfc_build_array_ref (mode, gfc_rank_cst[i], NULL_TREE);
-             gfc_add_modify (block, tmp,
-                             build_int_cst (unsigned_char_type_node,
-                                            GFC_CAF_ARR_REF_NONE));
-           }
-         break;
-       default:
-         gcc_unreachable ();
-       }
-
-      /* Set the size of the current type.  */
-      field = gfc_advance_chain (TYPE_FIELDS (reference_type), 2);
-      tmp = fold_build3_loc (input_location, COMPONENT_REF, TREE_TYPE (field),
-                            prev_caf_ref, field, NULL_TREE);
-      gfc_add_modify (block, tmp, fold_convert (TREE_TYPE (field),
-                                               TYPE_SIZE_UNIT (last_type)));
-
-      ref = ref->next;
-    }
-
-  if (prev_caf_ref != NULL_TREE)
-    {
-      field = gfc_advance_chain (TYPE_FIELDS (reference_type), 0);
-      tmp = fold_build3_loc (input_location, COMPONENT_REF, TREE_TYPE (field),
-                            prev_caf_ref, field, NULL_TREE);
-      gfc_add_modify (block, tmp, fold_convert (TREE_TYPE (field),
-                                                 null_pointer_node));
-    }
-  return caf_ref != NULL_TREE ? gfc_build_addr_expr (NULL_TREE, caf_ref)
-                             : NULL_TREE;
-}
+// static void
+// conv_caf_vector_subscript_elem (stmtblock_t *block, int i, tree desc,
+//                             tree lower, tree upper, tree stride,
+//                             tree vector, int kind, tree nvec)
+// {
+//   tree field, type, tmp;
+
+//   desc = gfc_build_array_ref (desc, gfc_rank_cst[i], NULL_TREE);
+//   type = TREE_TYPE (desc);
+
+//   field = gfc_advance_chain (TYPE_FIELDS (type), 0);
+//   tmp = fold_build3_loc (input_location, COMPONENT_REF, TREE_TYPE (field),
+//                      desc, field, NULL_TREE);
+//   gfc_add_modify (block, tmp, fold_convert (TREE_TYPE (field), nvec));
+
+//   /* Access union.  */
+//   field = gfc_advance_chain (TYPE_FIELDS (type), 1);
+//   desc = fold_build3_loc (input_location, COMPONENT_REF, TREE_TYPE (field),
+//                       desc, field, NULL_TREE);
+//   type = TREE_TYPE (desc);
+
+//   /* Access the inner struct.  */
+//   field = gfc_advance_chain (TYPE_FIELDS (type), vector != NULL_TREE ? 0 :
+//   1); desc = fold_build3_loc (input_location, COMPONENT_REF, TREE_TYPE
+//   (field),
+//                   desc, field, NULL_TREE);
+//   type = TREE_TYPE (desc);
+
+//   if (vector != NULL_TREE)
+//     {
+//       /* Set vector and kind.  */
+//       field = gfc_advance_chain (TYPE_FIELDS (type), 0);
+//       tmp = fold_build3_loc (input_location, COMPONENT_REF, TREE_TYPE
+//       (field),
+//                      desc, field, NULL_TREE);
+//       gfc_add_modify (block, tmp, fold_convert (TREE_TYPE (field), vector));
+//       field = gfc_advance_chain (TYPE_FIELDS (type), 1);
+//       tmp = fold_build3_loc (input_location, COMPONENT_REF, TREE_TYPE
+//       (field),
+//                      desc, field, NULL_TREE);
+//       gfc_add_modify (block, tmp, build_int_cst (integer_type_node, kind));
+//     }
+//   else
+//     {
+//       /* Set dim.lower/upper/stride.  */
+//       field = gfc_advance_chain (TYPE_FIELDS (type), 0);
+//       tmp = fold_build3_loc (input_location, COMPONENT_REF, TREE_TYPE
+//       (field),
+//                          desc, field, NULL_TREE);
+//       gfc_add_modify (block, tmp, fold_convert (TREE_TYPE (field), lower));
+
+//       field = gfc_advance_chain (TYPE_FIELDS (type), 1);
+//       tmp = fold_build3_loc (input_location, COMPONENT_REF, TREE_TYPE
+//       (field),
+//                          desc, field, NULL_TREE);
+//       gfc_add_modify (block, tmp, fold_convert (TREE_TYPE (field), upper));
+
+//       field = gfc_advance_chain (TYPE_FIELDS (type), 2);
+//       tmp = fold_build3_loc (input_location, COMPONENT_REF, TREE_TYPE
+//       (field),
+//                          desc, field, NULL_TREE);
+//       gfc_add_modify (block, tmp, fold_convert (TREE_TYPE (field), stride));
+//     }
+// }
+
+// static tree
+// conv_caf_vector_subscript (stmtblock_t *block, tree desc, gfc_array_ref *ar)
+// {
+//   gfc_se argse;
+//   tree var, lower, upper = NULL_TREE, stride = NULL_TREE, vector, nvec;
+//   tree lbound, ubound, tmp;
+//   int i;
+
+//   var = gfc_create_var (gfc_get_caf_vector_type (ar->dimen), "vector");
+
+//   for (i = 0; i < ar->dimen; i++)
+//     switch (ar->dimen_type[i])
+//       {
+//       case DIMEN_RANGE:
+//         if (ar->end[i])
+//       {
+//         gfc_init_se (&argse, NULL);
+//         gfc_conv_expr (&argse, ar->end[i]);
+//         gfc_add_block_to_block (block, &argse.pre);
+//         upper = gfc_evaluate_now (argse.expr, block);
+//       }
+//         else
+//       upper = gfc_conv_descriptor_ubound_get (desc, gfc_rank_cst[i]);
+//     if (ar->stride[i])
+//       {
+//         gfc_init_se (&argse, NULL);
+//         gfc_conv_expr (&argse, ar->stride[i]);
+//         gfc_add_block_to_block (block, &argse.pre);
+//         stride = gfc_evaluate_now (argse.expr, block);
+//       }
+//     else
+//       stride = gfc_index_one_node;
+
+//     /* Fall through.  */
+//       case DIMEN_ELEMENT:
+//     if (ar->start[i])
+//       {
+//         gfc_init_se (&argse, NULL);
+//         gfc_conv_expr (&argse, ar->start[i]);
+//         gfc_add_block_to_block (block, &argse.pre);
+//         lower = gfc_evaluate_now (argse.expr, block);
+//       }
+//     else
+//       lower = gfc_conv_descriptor_lbound_get (desc, gfc_rank_cst[i]);
+//     if (ar->dimen_type[i] == DIMEN_ELEMENT)
+//       {
+//         upper = lower;
+//         stride = gfc_index_one_node;
+//       }
+//     vector = NULL_TREE;
+//     nvec = size_zero_node;
+//     conv_caf_vector_subscript_elem (block, i, var, lower, upper, stride,
+//                                     vector, 0, nvec);
+//     break;
+
+//       case DIMEN_VECTOR:
+//     gfc_init_se (&argse, NULL);
+//     argse.descriptor_only = 1;
+//     gfc_conv_expr_descriptor (&argse, ar->start[i]);
+//     gfc_add_block_to_block (block, &argse.pre);
+//     vector = argse.expr;
+//     lbound = gfc_conv_descriptor_lbound_get (vector, gfc_rank_cst[0]);
+//     ubound = gfc_conv_descriptor_ubound_get (vector, gfc_rank_cst[0]);
+//     nvec = gfc_conv_array_extent_dim (lbound, ubound, NULL);
+//         tmp = gfc_conv_descriptor_stride_get (vector, gfc_rank_cst[0]);
+//     nvec = fold_build2_loc (input_location, TRUNC_DIV_EXPR,
+//                             TREE_TYPE (nvec), nvec, tmp);
+//     lower = gfc_index_zero_node;
+//     upper = gfc_index_zero_node;
+//     stride = gfc_index_zero_node;
+//     vector = gfc_conv_descriptor_data_get (vector);
+//     conv_caf_vector_subscript_elem (block, i, var, lower, upper, stride,
+//                                     vector, ar->start[i]->ts.kind, nvec);
+//     break;
+//       default:
+//     gcc_unreachable();
+//     }
+//   return gfc_build_addr_expr (NULL_TREE, var);
+// }
+
+// static tree
+// compute_component_offset (tree field, tree type)
+// {
+//   tree tmp;
+//   if (DECL_FIELD_BIT_OFFSET (field) != NULL_TREE
+//       && !integer_zerop (DECL_FIELD_BIT_OFFSET (field)))
+//     {
+//       tmp = fold_build2 (TRUNC_DIV_EXPR, type,
+//                      DECL_FIELD_BIT_OFFSET (field),
+//                      bitsize_unit_node);
+//       return fold_build2 (PLUS_EXPR, type, DECL_FIELD_OFFSET (field), tmp);
+//     }
+//   else
+//     return DECL_FIELD_OFFSET (field);
+// }
+
+// static tree
+// conv_expr_ref_to_caf_ref (stmtblock_t *block, gfc_expr *expr)
+// {
+//   gfc_ref *ref = expr->ref, *last_comp_ref;
+//   tree caf_ref = NULL_TREE, prev_caf_ref = NULL_TREE, reference_type, tmp,
+//   tmp2,
+//       field, last_type, inner_struct, mode, mode_rhs, dim_array, dim,
+//       dim_type, start, end, stride, vector, nvec;
+//   gfc_se se;
+//   bool ref_static_array = false;
+//   tree last_component_ref_tree = NULL_TREE;
+//   int i, last_type_n;
+
+//   if (expr->symtree)
+//     {
+//       last_component_ref_tree = expr->symtree->n.sym->backend_decl;
+//       ref_static_array = !expr->symtree->n.sym->attr.allocatable
+//       && !expr->symtree->n.sym->attr.pointer;
+//     }
+
+//   /* Prevent uninit-warning.  */
+//   reference_type = NULL_TREE;
+
+//   /* Skip refs upto the first coarray-ref.  */
+//   last_comp_ref = NULL;
+//   while (ref && (ref->type != REF_ARRAY || ref->u.ar.codimen == 0))
+//     {
+//       /* Remember the type of components skipped.  */
+//       if (ref->type == REF_COMPONENT)
+//     last_comp_ref = ref;
+//       ref = ref->next;
+//     }
+//   /* When a component was skipped, get the type information of the last
+//      component ref, else get the type from the symbol.  */
+//   if (last_comp_ref)
+//     {
+//       last_type = gfc_typenode_for_spec (&last_comp_ref->u.c.component->ts);
+//       last_type_n = last_comp_ref->u.c.component->ts.type;
+//     }
+//   else
+//     {
+//       last_type = gfc_typenode_for_spec (&expr->symtree->n.sym->ts);
+//       last_type_n = expr->symtree->n.sym->ts.type;
+//     }
+
+//   while (ref)
+//     {
+//       if (ref->type == REF_ARRAY && ref->u.ar.codimen > 0
+//       && ref->u.ar.dimen == 0)
+//     {
+//       /* Skip pure coindexes.  */
+//       ref = ref->next;
+//       continue;
+//     }
+//       tmp = gfc_create_var (gfc_get_caf_reference_type (), "caf_ref");
+//       reference_type = TREE_TYPE (tmp);
+
+//       if (caf_ref == NULL_TREE)
+//     caf_ref = tmp;
+
+//       /* Construct the chain of refs.  */
+//       if (prev_caf_ref != NULL_TREE)
+//     {
+//       field = gfc_advance_chain (TYPE_FIELDS (reference_type), 0);
+//       tmp2 = fold_build3_loc (input_location, COMPONENT_REF,
+//                               TREE_TYPE (field), prev_caf_ref, field,
+//                               NULL_TREE);
+//       gfc_add_modify (block, tmp2, gfc_build_addr_expr (TREE_TYPE (field),
+//                                                         tmp));
+//     }
+//       prev_caf_ref = tmp;
+
+//       switch (ref->type)
+//     {
+//     case REF_COMPONENT:
+//       last_type = gfc_typenode_for_spec (&ref->u.c.component->ts);
+//       last_type_n = ref->u.c.component->ts.type;
+//       /* Set the type of the ref.  */
+//       field = gfc_advance_chain (TYPE_FIELDS (reference_type), 1);
+//       tmp = fold_build3_loc (input_location, COMPONENT_REF,
+//                              TREE_TYPE (field), prev_caf_ref, field,
+//                              NULL_TREE);
+//       gfc_add_modify (block, tmp, build_int_cst (integer_type_node,
+//                                                  GFC_CAF_REF_COMPONENT));
+
+//       /* Ref the c in union u.  */
+//       field = gfc_advance_chain (TYPE_FIELDS (reference_type), 3);
+//       tmp = fold_build3_loc (input_location, COMPONENT_REF,
+//                              TREE_TYPE (field), prev_caf_ref, field,
+//                              NULL_TREE);
+//       field = gfc_advance_chain (TYPE_FIELDS (TREE_TYPE (field)), 0);
+//       inner_struct = fold_build3_loc (input_location, COMPONENT_REF,
+//                                    TREE_TYPE (field), tmp, field,
+//                                    NULL_TREE);
+
+//       /* Set the offset.  */
+//       field = gfc_advance_chain (TYPE_FIELDS (TREE_TYPE (inner_struct)), 0);
+//       tmp = fold_build3_loc (input_location, COMPONENT_REF,
+//                              TREE_TYPE (field), inner_struct, field,
+//                              NULL_TREE);
+//       /* Computing the offset is somewhat harder.  The bit_offset has to be
+//          taken into account.  When the bit_offset in the field_decl is non-
+//          null, divide it by the bitsize_unit and add it to the regular
+//          offset.  */
+//       tmp2 = compute_component_offset (ref->u.c.component->backend_decl,
+//                                        TREE_TYPE (tmp));
+//       gfc_add_modify (block, tmp, fold_convert (TREE_TYPE (tmp), tmp2));
+
+//       /* Set caf_token_offset.  */
+//       field = gfc_advance_chain (TYPE_FIELDS (TREE_TYPE (inner_struct)), 1);
+//       tmp = fold_build3_loc (input_location, COMPONENT_REF,
+//                              TREE_TYPE (field), inner_struct, field,
+//                              NULL_TREE);
+//       if ((ref->u.c.component->attr.allocatable
+//            || ref->u.c.component->attr.pointer)
+//           && ref->u.c.component->attr.dimension)
+//         {
+//           tree arr_desc_token_offset;
+//           /* Get the token field from the descriptor.  */
+//           arr_desc_token_offset = TREE_OPERAND (
+//                 gfc_conv_descriptor_token
+// (ref->u.c.component->backend_decl), 1);           arr_desc_token_offset
+// = compute_component_offset (arr_desc_token_offset,
+// TREE_TYPE (tmp));         tmp2 = fold_build2_loc (input_location, PLUS_EXPR,
+// TREE_TYPE (tmp2), tmp2,                                   
arr_desc_token_offset);
+//         }
+//       else if (ref->u.c.component->caf_token)
+//         tmp2 = compute_component_offset (gfc_comp_caf_token (
+//                                            ref->u.c.component),
+//                                          TREE_TYPE (tmp));
+//       else
+//         tmp2 = integer_zero_node;
+//       gfc_add_modify (block, tmp, fold_convert (TREE_TYPE (tmp), tmp2));
+
+//       /* Remember whether this ref was to a non-allocatable/non-pointer
+//          component so the next array ref can be tailored correctly.  */
+//       ref_static_array = !ref->u.c.component->attr.allocatable
+//           && !ref->u.c.component->attr.pointer;
+//       last_component_ref_tree = ref_static_array
+//           ? ref->u.c.component->backend_decl : NULL_TREE;
+//       break;
+//     case REF_ARRAY:
+//       if (ref_static_array && ref->u.ar.as->type == AS_DEFERRED)
+//         ref_static_array = false;
+//       /* Set the type of the ref.  */
+//       field = gfc_advance_chain (TYPE_FIELDS (reference_type), 1);
+//       tmp = fold_build3_loc (input_location, COMPONENT_REF,
+//                              TREE_TYPE (field), prev_caf_ref, field,
+//                              NULL_TREE);
+//       gfc_add_modify (block, tmp, build_int_cst (integer_type_node,
+//                                                  ref_static_array
+//                                                  ? GFC_CAF_REF_STATIC_ARRAY
+//                                                  : GFC_CAF_REF_ARRAY));
+
+//       /* Ref the a in union u.  */
+//       field = gfc_advance_chain (TYPE_FIELDS (reference_type), 3);
+//       tmp = fold_build3_loc (input_location, COMPONENT_REF,
+//                              TREE_TYPE (field), prev_caf_ref, field,
+//                              NULL_TREE);
+//       field = gfc_advance_chain (TYPE_FIELDS (TREE_TYPE (field)), 1);
+//       inner_struct = fold_build3_loc (input_location, COMPONENT_REF,
+//                                    TREE_TYPE (field), tmp, field,
+//                                    NULL_TREE);
+
+//       /* Set the static_array_type in a for static arrays.  */
+//       if (ref_static_array)
+//         {
+//           field = gfc_advance_chain (TYPE_FIELDS (TREE_TYPE (inner_struct)),
+//                                      1);
+//           tmp = fold_build3_loc (input_location, COMPONENT_REF,
+//                                  TREE_TYPE (field), inner_struct, field,
+//                                  NULL_TREE);
+//           gfc_add_modify (block, tmp, build_int_cst (TREE_TYPE (tmp),
+//                                                      last_type_n));
+//         }
+//       /* Ref the mode in the inner_struct.  */
+//       field = gfc_advance_chain (TYPE_FIELDS (TREE_TYPE (inner_struct)), 0);
+//       mode = fold_build3_loc (input_location, COMPONENT_REF,
+//                               TREE_TYPE (field), inner_struct, field,
+//                               NULL_TREE);
+//       /* Ref the dim in the inner_struct.  */
+//       field = gfc_advance_chain (TYPE_FIELDS (TREE_TYPE (inner_struct)), 2);
+//       dim_array = fold_build3_loc (input_location, COMPONENT_REF,
+//                                    TREE_TYPE (field), inner_struct, field,
+//                                    NULL_TREE);
+//       for (i = 0; i < ref->u.ar.dimen; ++i)
+//         {
+//           /* Ref dim i.  */
+//           dim = gfc_build_array_ref (dim_array, gfc_rank_cst[i], NULL_TREE);
+//           dim_type = TREE_TYPE (dim);
+//           mode_rhs = start = end = stride = NULL_TREE;
+//           switch (ref->u.ar.dimen_type[i])
+//             {
+//             case DIMEN_RANGE:
+//               if (ref->u.ar.end[i])
+//                 {
+//                   gfc_init_se (&se, NULL);
+//                   gfc_conv_expr (&se, ref->u.ar.end[i]);
+//                   gfc_add_block_to_block (block, &se.pre);
+//                   if (ref_static_array)
+//                     {
+//                       /* Make the index zero-based, when reffing a static
+//                          array.  */
+//                       end = se.expr;
+//                       gfc_init_se (&se, NULL);
+//                       gfc_conv_expr (&se, ref->u.ar.as->lower[i]);
+//                       gfc_add_block_to_block (block, &se.pre);
+//                       se.expr = fold_build2 (MINUS_EXPR,
+//                                              gfc_array_index_type,
+//                                              end, fold_convert (
+//                                                gfc_array_index_type,
+//                                                se.expr));
+//                     }
+//                   end = gfc_evaluate_now (fold_convert (
+//                                             gfc_array_index_type,
+//                                             se.expr),
+//                                           block);
+//                 }
+//               else if (ref_static_array)
+//                 end = fold_build2 (MINUS_EXPR,
+//                                    gfc_array_index_type,
+//                                    gfc_conv_array_ubound (
+//                                      last_component_ref_tree, i),
+//                                    gfc_conv_array_lbound (
+//                                      last_component_ref_tree, i));
+//               else
+//                 {
+//                   end = NULL_TREE;
+//                   mode_rhs = build_int_cst (unsigned_char_type_node,
+//                                             GFC_CAF_ARR_REF_OPEN_END);
+//                 }
+//               if (ref->u.ar.stride[i])
+//                 {
+//                   gfc_init_se (&se, NULL);
+//                   gfc_conv_expr (&se, ref->u.ar.stride[i]);
+//                   gfc_add_block_to_block (block, &se.pre);
+//                   stride = gfc_evaluate_now (fold_convert (
+//                                                gfc_array_index_type,
+//                                                se.expr),
+//                                              block);
+//                   if (ref_static_array)
+//                     {
+//                       /* Make the index zero-based, when reffing a static
+//                          array.  */
+//                       stride = fold_build2 (MULT_EXPR,
+//                                             gfc_array_index_type,
+//                                             gfc_conv_array_stride (
+//                                               last_component_ref_tree,
+//                                               i),
+//                                             stride);
+//                       gcc_assert (end != NULL_TREE);
+//                       /* Multiply with the product of array's stride and
+//                          the step of the ref to a virtual upper bound.
+//                          We cannot compute the actual upper bound here or
+//                          the caflib would compute the extend
+//                          incorrectly.  */
+//                       end = fold_build2 (MULT_EXPR, gfc_array_index_type,
+//                                          end, gfc_conv_array_stride (
+//                                            last_component_ref_tree,
+//                                            i));
+//                       end = gfc_evaluate_now (end, block);
+//                       stride = gfc_evaluate_now (stride, block);
+//                     }
+//                 }
+//               else if (ref_static_array)
+//                 {
+//                   stride = gfc_conv_array_stride (last_component_ref_tree,
+//                                                   i);
+//                   end = fold_build2 (MULT_EXPR, gfc_array_index_type,
+//                                      end, stride);
+//                   end = gfc_evaluate_now (end, block);
+//                 }
+//               else
+//                 /* Always set a ref stride of one to make caflib's
+//                    handling easier.  */
+//                 stride = gfc_index_one_node;
+
+//               /* Fall through.  */
+//             case DIMEN_ELEMENT:
+//               if (ref->u.ar.start[i])
+//                 {
+//                   gfc_init_se (&se, NULL);
+//                   gfc_conv_expr (&se, ref->u.ar.start[i]);
+//                   gfc_add_block_to_block (block, &se.pre);
+//                   if (ref_static_array)
+//                     {
+//                       /* Make the index zero-based, when reffing a static
+//                          array.  */
+//                       start = fold_convert (gfc_array_index_type, se.expr);
+//                       gfc_init_se (&se, NULL);
+//                       gfc_conv_expr (&se, ref->u.ar.as->lower[i]);
+//                       gfc_add_block_to_block (block, &se.pre);
+//                       se.expr = fold_build2 (MINUS_EXPR,
+//                                              gfc_array_index_type,
+//                                              start, fold_convert (
+//                                                gfc_array_index_type,
+//                                                se.expr));
+//                       /* Multiply with the stride.  */
+//                       se.expr = fold_build2 (MULT_EXPR,
+//                                              gfc_array_index_type,
+//                                              se.expr,
+//                                              gfc_conv_array_stride (
+//                                                last_component_ref_tree,
+//                                                i));
+//                     }
+//                   start = gfc_evaluate_now (fold_convert (
+//                                               gfc_array_index_type,
+//                                               se.expr),
+//                                             block);
+//                   if (mode_rhs == NULL_TREE)
+//                     mode_rhs = build_int_cst (unsigned_char_type_node,
+//                                               ref->u.ar.dimen_type[i]
+//                                               == DIMEN_ELEMENT
+//                                               ? GFC_CAF_ARR_REF_SINGLE
+//                                               : GFC_CAF_ARR_REF_RANGE);
+//                 }
+//               else if (ref_static_array)
+//                 {
+//                   start = integer_zero_node;
+//                   mode_rhs = build_int_cst (unsigned_char_type_node,
+//                                             ref->u.ar.start[i] == NULL
+//                                             ? GFC_CAF_ARR_REF_FULL
+//                                             : GFC_CAF_ARR_REF_RANGE);
+//                 }
+//               else if (end == NULL_TREE)
+//                 mode_rhs = build_int_cst (unsigned_char_type_node,
+//                                           GFC_CAF_ARR_REF_FULL);
+//               else
+//                 mode_rhs = build_int_cst (unsigned_char_type_node,
+//                                           GFC_CAF_ARR_REF_OPEN_START);
+
+//               /* Ref the s in dim.  */
+//               field = gfc_advance_chain (TYPE_FIELDS (dim_type), 0);
+//               tmp = fold_build3_loc (input_location, COMPONENT_REF,
+//                                      TREE_TYPE (field), dim, field,
+//                                      NULL_TREE);
+
+//               /* Set start in s.  */
+//               if (start != NULL_TREE)
+//                 {
+//                   field = gfc_advance_chain (TYPE_FIELDS (TREE_TYPE (tmp)),
+//                                              0);
+//                   tmp2 = fold_build3_loc (input_location, COMPONENT_REF,
+//                                           TREE_TYPE (field), tmp, field,
+//                                           NULL_TREE);
+//                   gfc_add_modify (block, tmp2,
+//                                   fold_convert (TREE_TYPE (tmp2), start));
+//                 }
+
+//               /* Set end in s.  */
+//               if (end != NULL_TREE)
+//                 {
+//                   field = gfc_advance_chain (TYPE_FIELDS (TREE_TYPE (tmp)),
+//                                              1);
+//                   tmp2 = fold_build3_loc (input_location, COMPONENT_REF,
+//                                           TREE_TYPE (field), tmp, field,
+//                                           NULL_TREE);
+//                   gfc_add_modify (block, tmp2,
+//                                   fold_convert (TREE_TYPE (tmp2), end));
+//                 }
+
+//               /* Set end in s.  */
+//               if (stride != NULL_TREE)
+//                 {
+//                   field = gfc_advance_chain (TYPE_FIELDS (TREE_TYPE (tmp)),
+//                                              2);
+//                   tmp2 = fold_build3_loc (input_location, COMPONENT_REF,
+//                                           TREE_TYPE (field), tmp, field,
+//                                           NULL_TREE);
+//                   gfc_add_modify (block, tmp2,
+//                                   fold_convert (TREE_TYPE (tmp2), stride));
+//                 }
+//               break;
+//             case DIMEN_VECTOR:
+//               /* TODO: In case of static array.  */
+//               gcc_assert (!ref_static_array);
+//               mode_rhs = build_int_cst (unsigned_char_type_node,
+//                                         GFC_CAF_ARR_REF_VECTOR);
+//               gfc_init_se (&se, NULL);
+//               se.descriptor_only = 1;
+//               gfc_conv_expr_descriptor (&se, ref->u.ar.start[i]);
+//               gfc_add_block_to_block (block, &se.pre);
+//               vector = se.expr;
+//               tmp = gfc_conv_descriptor_lbound_get (vector,
+//                                                     gfc_rank_cst[0]);
+//               tmp2 = gfc_conv_descriptor_ubound_get (vector,
+//                                                      gfc_rank_cst[0]);
+//               nvec = gfc_conv_array_extent_dim (tmp, tmp2, NULL);
+//               tmp = gfc_conv_descriptor_stride_get (vector,
+//                                                     gfc_rank_cst[0]);
+//               nvec = fold_build2_loc (input_location, TRUNC_DIV_EXPR,
+//                                       TREE_TYPE (nvec), nvec, tmp);
+//               vector = gfc_conv_descriptor_data_get (vector);
+
+//               /* Ref the v in dim.  */
+//               field = gfc_advance_chain (TYPE_FIELDS (dim_type), 1);
+//               tmp = fold_build3_loc (input_location, COMPONENT_REF,
+//                                      TREE_TYPE (field), dim, field,
+//                                      NULL_TREE);
+
+//               /* Set vector in v.  */
+//               field = gfc_advance_chain (TYPE_FIELDS (TREE_TYPE (tmp)), 0);
+//               tmp2 = fold_build3_loc (input_location, COMPONENT_REF,
+//                                       TREE_TYPE (field), tmp, field,
+//                                       NULL_TREE);
+//               gfc_add_modify (block, tmp2, fold_convert (TREE_TYPE (tmp2),
+//                                                          vector));
+
+//               /* Set nvec in v.  */
+//               field = gfc_advance_chain (TYPE_FIELDS (TREE_TYPE (tmp)), 1);
+//               tmp2 = fold_build3_loc (input_location, COMPONENT_REF,
+//                                       TREE_TYPE (field), tmp, field,
+//                                       NULL_TREE);
+//               gfc_add_modify (block, tmp2, fold_convert (TREE_TYPE (tmp2),
+//                                                          nvec));
+
+//               /* Set kind in v.  */
+//               field = gfc_advance_chain (TYPE_FIELDS (TREE_TYPE (tmp)), 2);
+//               tmp2 = fold_build3_loc (input_location, COMPONENT_REF,
+//                                       TREE_TYPE (field), tmp, field,
+//                                       NULL_TREE);
+//               gfc_add_modify (block, tmp2, build_int_cst (integer_type_node,
+//                                               ref->u.ar.start[i]->ts.kind));
+//               break;
+//             default:
+//               gcc_unreachable ();
+//             }
+//           /* Set the mode for dim i.  */
+//           tmp = gfc_build_array_ref (mode, gfc_rank_cst[i], NULL_TREE);
+//           gfc_add_modify (block, tmp, fold_convert (TREE_TYPE (tmp),
+//                                                     mode_rhs));
+//         }
+
+//       /* Set the mode for dim i+1 to GFC_ARR_REF_NONE.  */
+//       if (i < GFC_MAX_DIMENSIONS)
+//         {
+//           tmp = gfc_build_array_ref (mode, gfc_rank_cst[i], NULL_TREE);
+//           gfc_add_modify (block, tmp,
+//                           build_int_cst (unsigned_char_type_node,
+//                                          GFC_CAF_ARR_REF_NONE));
+//         }
+//       break;
+//     default:
+//       gcc_unreachable ();
+//     }
+
+//       /* Set the size of the current type.  */
+//       field = gfc_advance_chain (TYPE_FIELDS (reference_type), 2);
+//       tmp = fold_build3_loc (input_location, COMPONENT_REF, TREE_TYPE
+//       (field),
+//                          prev_caf_ref, field, NULL_TREE);
+//       gfc_add_modify (block, tmp, fold_convert (TREE_TYPE (field),
+//                                             TYPE_SIZE_UNIT (last_type)));
+
+//       ref = ref->next;
+//     }
+
+//   if (prev_caf_ref != NULL_TREE)
+//     {
+//       field = gfc_advance_chain (TYPE_FIELDS (reference_type), 0);
+//       tmp = fold_build3_loc (input_location, COMPONENT_REF, TREE_TYPE
+//       (field),
+//                          prev_caf_ref, field, NULL_TREE);
+//       gfc_add_modify (block, tmp, fold_convert (TREE_TYPE (field),
+//                                               null_pointer_node));
+//     }
+//   return caf_ref != NULL_TREE ? gfc_build_addr_expr (NULL_TREE, caf_ref)
+//                           : NULL_TREE;
+// }
 
 static int caf_call_cnt = 0;
 
@@ -1802,16 +1806,48 @@ conv_shape_to_cst (gfc_expr *e)
   return fold_convert (size_type_node, tmp);
 }
 
+static void
+conv_stat_and_team (stmtblock_t *block, gfc_expr *expr, tree *stat, tree *team)
+{
+  gfc_expr *stat_e, *team_e;
+
+  stat_e = gfc_find_stat_co (expr);
+  if (stat_e)
+    {
+      gfc_se stat_se;
+      gfc_init_se (&stat_se, NULL);
+      gfc_conv_expr_reference (&stat_se, stat_e);
+      *stat = stat_se.expr;
+      gfc_add_block_to_block (block, &stat_se.pre);
+      gfc_add_block_to_block (block, &stat_se.post);
+    }
+  else
+    *stat = null_pointer_node;
+
+  team_e = gfc_find_team_co (expr);
+  if (team_e)
+    {
+      gfc_se team_se;
+      gfc_init_se (&team_se, NULL);
+      gfc_conv_expr_reference (&team_se, team_e);
+      *team = team_se.expr;
+      gfc_add_block_to_block (block, &team_se.pre);
+      gfc_add_block_to_block (block, &team_se.post);
+    }
+  else
+    *team = null_pointer_node;
+}
+
 /* Get data from a remote coarray.  */
 
 static void
 gfc_conv_intrinsic_caf_get (gfc_se *se, gfc_expr *expr, tree lhs,
                            bool may_realloc, symbol_attribute *caf_attr)
 {
-  gfc_expr *array_expr, *tmp_stat;
+  gfc_expr *array_expr;
   tree caf_decl, token, image_index, tmp, res_var, type, stat, dest_size,
     dest_data, opt_dest_desc, get_fn_index_tree, add_data_tree, add_data_size,
-    opt_src_desc, opt_src_charlen, opt_dest_charlen;
+    opt_src_desc, opt_src_charlen, opt_dest_charlen, team;
   symbol_attribute caf_attr_store;
   gfc_namespace *ns;
   gfc_expr *get_fn_hash = expr->value.function.actual->next->expr,
@@ -1842,19 +1878,7 @@ gfc_conv_intrinsic_caf_get (gfc_se *se, gfc_expr *expr, 
tree lhs,
 
   res_var = lhs;
 
-  tmp_stat = gfc_find_stat_co (expr);
-
-  if (tmp_stat)
-    {
-      gfc_se stat_se;
-      gfc_init_se (&stat_se, NULL);
-      gfc_conv_expr_reference (&stat_se, tmp_stat);
-      stat = stat_se.expr;
-      gfc_add_block_to_block (&se->pre, &stat_se.pre);
-      gfc_add_block_to_block (&se->post, &stat_se.post);
-    }
-  else
-    stat = null_pointer_node;
+  conv_stat_and_team (&se->pre, expr, &stat, &team);
 
   get_fn_index_tree
     = conv_caf_func_index (&se->pre, ns, "__caf_get_from_remote_fn_index_%d",
@@ -1958,7 +1982,7 @@ gfc_conv_intrinsic_caf_get (gfc_se *se, gfc_expr *expr, 
tree lhs,
     input_location, gfor_fndecl_caf_get_from_remote, 15, token, opt_src_desc,
     opt_src_charlen, image_index, dest_size, dest_data, opt_dest_charlen,
     opt_dest_desc, constant_boolean_node (may_realloc, boolean_type_node),
-    get_fn_index_tree, add_data_tree, add_data_size, stat, null_pointer_node,
+    get_fn_index_tree, add_data_tree, add_data_size, stat, team,
     null_pointer_node);
 
   gfc_add_expr_to_block (&se->pre, tmp);
@@ -2014,8 +2038,7 @@ gfc_conv_intrinsic_caf_is_present_remote (gfc_se *se, 
gfc_expr *e)
 static tree
 conv_caf_send_to_remote (gfc_code *code)
 {
-  gfc_expr *lhs_expr, *rhs_expr, *lhs_hash, *receiver_fn_expr, *tmp_stat,
-    *tmp_team;
+  gfc_expr *lhs_expr, *rhs_expr, *lhs_hash, *receiver_fn_expr;
   gfc_symbol *add_data_sym;
   gfc_se lhs_se, rhs_se;
   stmtblock_t block;
@@ -2041,9 +2064,6 @@ conv_caf_send_to_remote (gfc_code *code)
 
   gfc_init_block (&block);
 
-  lhs_stat = null_pointer_node;
-  lhs_team = null_pointer_node;
-
   /* LHS.  */
   gfc_init_se (&lhs_se, NULL);
   caf_decl = gfc_get_tree_for_caf_expr (lhs_expr);
@@ -2089,6 +2109,7 @@ conv_caf_send_to_remote (gfc_code *code)
   gfc_init_se (&rhs_se, NULL);
   if (rhs_expr->rank == 0)
     {
+      rhs_se.want_pointer = rhs_expr->ts.type == BT_CHARACTER;
       gfc_conv_expr (&rhs_se, rhs_expr);
       gfc_add_block_to_block (&block, &rhs_se.pre);
       opt_rhs_desc = null_pointer_node;
@@ -2111,7 +2132,7 @@ conv_caf_send_to_remote (gfc_code *code)
                                   gfc_trans_force_lval (&block, rhs_se.expr));
          opt_rhs_charlen
            = build_zero_cst (build_pointer_type (size_type_node));
-         rhs_size = rhs_se.expr->typed.type->type_common.size_unit;
+         rhs_size = TREE_TYPE (rhs_se.expr)->type_common.size_unit;
        }
     }
   else
@@ -2149,29 +2170,7 @@ conv_caf_send_to_remote (gfc_code *code)
     }
   gfc_add_block_to_block (&block, &rhs_se.pre);
 
-  tmp_stat = gfc_find_stat_co (lhs_expr);
-
-  if (tmp_stat)
-    {
-      gfc_se stat_se;
-      gfc_init_se (&stat_se, NULL);
-      gfc_conv_expr_reference (&stat_se, tmp_stat);
-      lhs_stat = stat_se.expr;
-      gfc_add_block_to_block (&block, &stat_se.pre);
-      gfc_add_block_to_block (&block, &stat_se.post);
-    }
-
-  tmp_team = gfc_find_team_co (lhs_expr);
-
-  if (tmp_team)
-    {
-      gfc_se team_se;
-      gfc_init_se (&team_se, NULL);
-      gfc_conv_expr_reference (&team_se, tmp_team);
-      lhs_team = team_se.expr;
-      gfc_add_block_to_block (&block, &team_se.pre);
-      gfc_add_block_to_block (&block, &team_se.post);
-    }
+  conv_stat_and_team (&block, lhs_expr, &lhs_stat, &lhs_team);
 
   receiver_fn_index_tree
     = conv_caf_func_index (&block, ns, "__caf_send_to_remote_fn_index_%d",
@@ -2203,447 +2202,225 @@ conv_caf_send_to_remote (gfc_code *code)
   return gfc_finish_block (&block);
 }
 
-static bool
-has_ref_after_cafref (gfc_expr *expr)
-{
-  for (gfc_ref *ref = expr->ref; ref; ref = ref->next)
-    if (ref->type == REF_ARRAY && ref->u.ar.codimen)
-      return ref->next;
-  return false;
-}
+// static bool
+// has_ref_after_cafref (gfc_expr *expr)
+// {
+//   for (gfc_ref *ref = expr->ref; ref; ref = ref->next)
+//     if (ref->type == REF_ARRAY && ref->u.ar.codimen)
+//       return ref->next;
+//   return false;
+// }
 
 /* Send-get data to a remote coarray.  */
 
 static tree
 conv_caf_sendget (gfc_code *code)
 {
-  gfc_expr *lhs_expr, *rhs_expr, *tmp_stat, *tmp_team;
-  gfc_se lhs_se, rhs_se;
+  /* lhs stuff  */
+  gfc_expr *lhs_expr, *lhs_hash, *receiver_fn_expr;
+  gfc_symbol *lhs_add_data_sym;
+  gfc_se lhs_se;
+  tree lhs_caf_decl, lhs_token, opt_lhs_charlen,
+    opt_lhs_desc = NULL_TREE, receiver_fn_index_tree, lhs_image_index,
+    lhs_add_data_tree, lhs_add_data_size, lhs_stat, lhs_team;
+  int transfer_rank;
+
+  /* rhs stuff  */
+  gfc_expr *rhs_expr, *rhs_hash, *sender_fn_expr;
+  gfc_symbol *rhs_add_data_sym;
+  gfc_se rhs_se;
+  tree rhs_caf_decl, rhs_token, opt_rhs_charlen,
+    opt_rhs_desc = NULL_TREE, sender_fn_index_tree, rhs_image_index,
+    rhs_add_data_tree, rhs_add_data_size, rhs_stat, rhs_team;
+
+  /* shared  */
   stmtblock_t block;
-  tree caf_decl, token, offset, image_index, tmp, lhs_kind, rhs_kind;
-  tree may_require_tmp, src_stat, dst_stat, dst_team;
-  tree lhs_type = NULL_TREE;
-  tree vec = null_pointer_node, rhs_vec = null_pointer_node;
-  symbol_attribute lhs_caf_attr, rhs_caf_attr;
-  bool lhs_is_coindexed, rhs_is_coindexed;
+  gfc_namespace *ns;
+  tree tmp, rhs_size;
 
   gcc_assert (flag_coarray == GFC_FCOARRAY_LIB);
+  gcc_assert (code->resolved_isym->id == GFC_ISYM_CAF_SENDGET);
+
+  lhs_expr = code->ext.actual->expr;
+  rhs_expr = code->ext.actual->next->expr;
+  lhs_hash = code->ext.actual->next->next->expr;
+  receiver_fn_expr = code->ext.actual->next->next->next->expr;
+  rhs_hash = code->ext.actual->next->next->next->next->expr;
+  sender_fn_expr = code->ext.actual->next->next->next->next->next->expr;
+
+  lhs_add_data_sym = receiver_fn_expr->symtree->n.sym->formal->sym;
+  rhs_add_data_sym = sender_fn_expr->symtree->n.sym->formal->sym;
+
+  ns = lhs_expr->expr_type == EXPR_VARIABLE
+          && !lhs_expr->symtree->n.sym->attr.associate_var
+        ? lhs_expr->symtree->n.sym->ns
+        : gfc_current_ns;
 
-  lhs_expr
-    = code->ext.actual->expr->expr_type == EXPR_FUNCTION
-         && code->ext.actual->expr->value.function.isym->id == GFC_ISYM_CAF_GET
-       ? code->ext.actual->expr->value.function.actual->expr
-       : code->ext.actual->expr;
-  rhs_expr = code->ext.actual->next->expr->expr_type == EXPR_FUNCTION
-                && code->ext.actual->next->expr->value.function.isym->id
-                     == GFC_ISYM_CAF_GET
-              ? code->ext.actual->next->expr->value.function.actual->expr
-              : code->ext.actual->next->expr;
-  lhs_is_coindexed = gfc_is_coindexed (lhs_expr);
-  rhs_is_coindexed = gfc_is_coindexed (rhs_expr);
-  may_require_tmp = gfc_check_dependency (lhs_expr, rhs_expr, true) == 0
-                   ? boolean_false_node : boolean_true_node;
   gfc_init_block (&block);
 
-  lhs_caf_attr = gfc_caf_attr (lhs_expr);
-  rhs_caf_attr = gfc_caf_attr (rhs_expr);
-  src_stat = dst_stat = null_pointer_node;
-  dst_team = null_pointer_node;
+  lhs_stat = null_pointer_node;
+  lhs_team = null_pointer_node;
+  rhs_stat = null_pointer_node;
+  rhs_team = null_pointer_node;
 
   /* LHS.  */
   gfc_init_se (&lhs_se, NULL);
+  lhs_caf_decl = gfc_get_tree_for_caf_expr (lhs_expr);
+  if (TREE_CODE (TREE_TYPE (lhs_caf_decl)) == REFERENCE_TYPE)
+    lhs_caf_decl = build_fold_indirect_ref_loc (input_location, lhs_caf_decl);
   if (lhs_expr->rank == 0)
     {
-      if (lhs_expr->ts.type == BT_CHARACTER && lhs_expr->ts.deferred)
+      if (lhs_expr->ts.type == BT_CHARACTER)
        {
-         lhs_se.expr = gfc_get_tree_for_caf_expr (lhs_expr);
-         if (!POINTER_TYPE_P (TREE_TYPE (lhs_se.expr)))
-           lhs_se.expr = gfc_build_addr_expr (NULL_TREE, lhs_se.expr);
+         gfc_conv_string_length (lhs_expr->ts.u.cl, lhs_expr, &block);
+         lhs_se.string_length = lhs_expr->ts.u.cl->backend_decl;
+         opt_lhs_charlen = gfc_build_addr_expr (
+           NULL_TREE, gfc_trans_force_lval (&block, lhs_se.string_length));
        }
       else
-       {
-         symbol_attribute attr;
-         gfc_clear_attr (&attr);
-         gfc_conv_expr (&lhs_se, lhs_expr);
-         lhs_type = TREE_TYPE (lhs_se.expr);
-         if (lhs_is_coindexed)
-           lhs_se.expr = gfc_conv_scalar_to_descriptor (&lhs_se, lhs_se.expr,
-                                                        attr);
-         lhs_se.expr = gfc_build_addr_expr (NULL_TREE, lhs_se.expr);
-       }
-    }
-  else if ((lhs_caf_attr.alloc_comp || lhs_caf_attr.pointer_comp)
-          && lhs_caf_attr.codimension)
-    {
-      lhs_se.want_pointer = 1;
-      gfc_conv_expr_descriptor (&lhs_se, lhs_expr);
-      /* Using gfc_conv_expr_descriptor, we only get the descriptor, but that
-        has the wrong type if component references are done.  */
-      lhs_type = gfc_typenode_for_spec (&lhs_expr->ts);
-      tmp = build_fold_indirect_ref_loc (input_location, lhs_se.expr);
-      gfc_add_modify (&lhs_se.pre, gfc_conv_descriptor_dtype (tmp),
-                     gfc_get_dtype_rank_type (
-                       gfc_has_vector_subscript (lhs_expr)
-                       ? gfc_find_array_ref (lhs_expr)->dimen
-                       : lhs_expr->rank,
-                     lhs_type));
+       opt_lhs_charlen = build_zero_cst (build_pointer_type (size_type_node));
+      opt_lhs_desc = null_pointer_node;
     }
   else
     {
-      bool has_vector = gfc_has_vector_subscript (lhs_expr);
-
-      if (lhs_is_coindexed || !has_vector)
-       {
-         /* If has_vector, pass descriptor for whole array and the
-            vector bounds separately.  */
-         gfc_array_ref *ar, ar2;
-         bool has_tmp_lhs_array = false;
-         if (has_vector)
-           {
-             has_tmp_lhs_array = true;
-             ar = gfc_find_array_ref (lhs_expr);
-             ar2 = *ar;
-             memset (ar, '\0', sizeof (*ar));
-             ar->as = ar2.as;
-             ar->type = AR_FULL;
-           }
-         lhs_se.want_pointer = 1;
-         gfc_conv_expr_descriptor (&lhs_se, lhs_expr);
-         /* Using gfc_conv_expr_descriptor, we only get the descriptor, but
-            that has the wrong type if component references are done.  */
-         lhs_type = gfc_typenode_for_spec (&lhs_expr->ts);
-         tmp = build_fold_indirect_ref_loc (input_location, lhs_se.expr);
-         gfc_add_modify (&lhs_se.pre, gfc_conv_descriptor_dtype (tmp),
-                         gfc_get_dtype_rank_type (has_vector ? ar2.dimen
-                                                             : lhs_expr->rank,
-                                                  lhs_type));
-         if (has_tmp_lhs_array)
-           {
-             vec = conv_caf_vector_subscript (&block, lhs_se.expr, &ar2);
-             *ar = ar2;
-           }
-       }
-      else if (rhs_is_coindexed)
-       {
-         /* Special casing for arr1 ([...]) = arr2[...], i.e. caf_get to
-            indexed array expression.  This is rewritten to:
-
-            tmp_array = arr2[...]
-            arr1 ([...]) = tmp_array
-
-            because using the standard gfc_conv_expr (lhs_expr) did the
-            assignment with lhs and rhs exchanged.  */
-
-         gfc_ss *lss_for_tmparray, *lss_real;
-         gfc_loopinfo loop;
-         gfc_se se;
-         stmtblock_t body;
-         tree tmparr_desc, src;
-         tree index = gfc_index_zero_node;
-         tree stride = gfc_index_zero_node;
-         int n;
-
-         /* Walk both sides of the assignment, once to get the shape of the
-            temporary array to create right.  */
-         lss_for_tmparray = gfc_walk_expr (lhs_expr);
-         /* And a second time to be able to create an assignment of the
-            temporary to the lhs_expr.  gfc_trans_create_temp_array replaces
-            the tree in the descriptor with the one for the temporary
-            array.  */
-         lss_real = gfc_walk_expr (lhs_expr);
-         gfc_init_loopinfo (&loop);
-         gfc_add_ss_to_loop (&loop, lss_for_tmparray);
-         gfc_add_ss_to_loop (&loop, lss_real);
-         gfc_conv_ss_startstride (&loop);
-         gfc_conv_loop_setup (&loop, &lhs_expr->where);
-         lhs_type = gfc_typenode_for_spec (&lhs_expr->ts);
-         gfc_trans_create_temp_array (&lhs_se.pre, &lhs_se.post,
-                                      lss_for_tmparray, lhs_type, NULL_TREE,
-                                      false, true, false,
-                                      &lhs_expr->where);
-         tmparr_desc = lss_for_tmparray->info->data.array.descriptor;
-         gfc_start_scalarized_body (&loop, &body);
-         gfc_init_se (&se, NULL);
-         gfc_copy_loopinfo_to_se (&se, &loop);
-         se.ss = lss_real;
-         gfc_conv_expr (&se, lhs_expr);
-         gfc_add_block_to_block (&body, &se.pre);
-
-         /* Walk over all indexes of the loop.  */
-         for (n = loop.dimen - 1; n > 0; --n)
-           {
-             tmp = loop.loopvar[n];
-             tmp = fold_build2_loc (input_location, MINUS_EXPR,
-                                    gfc_array_index_type, tmp, loop.from[n]);
-             tmp = fold_build2_loc (input_location, PLUS_EXPR,
-                                    gfc_array_index_type, tmp, index);
-
-             stride = fold_build2_loc (input_location, MINUS_EXPR,
-                                       gfc_array_index_type,
-                                       loop.to[n - 1], loop.from[n - 1]);
-             stride = fold_build2_loc (input_location, PLUS_EXPR,
-                                       gfc_array_index_type,
-                                       stride, gfc_index_one_node);
-
-             index = fold_build2_loc (input_location, MULT_EXPR,
-                                      gfc_array_index_type, tmp, stride);
-           }
-
-         index = fold_build2_loc (input_location, MINUS_EXPR,
-                                  gfc_array_index_type,
-                                  index, loop.from[0]);
-
-         index = fold_build2_loc (input_location, PLUS_EXPR,
-                                  gfc_array_index_type,
-                                  loop.loopvar[0], index);
-
-         src = build_fold_indirect_ref (gfc_conv_array_data (tmparr_desc));
-         src = gfc_build_array_ref (src, index, NULL);
-         /* Now create the assignment of lhs_expr = tmp_array.  */
-         gfc_add_modify (&body, se.expr, src);
-         gfc_add_block_to_block (&body, &se.post);
-         lhs_se.expr = gfc_build_addr_expr (NULL_TREE, tmparr_desc);
-         gfc_trans_scalarizing_loops (&loop, &body);
-         gfc_add_block_to_block (&loop.pre, &loop.post);
-         gfc_add_expr_to_block (&lhs_se.post, gfc_finish_block (&loop.pre));
-         gfc_free_ss (lss_for_tmparray);
-         gfc_free_ss (lss_real);
-       }
-    }
-
-  lhs_kind = build_int_cst (integer_type_node, lhs_expr->ts.kind);
-
-  /* Special case: RHS is a coarray but LHS is not; this code path avoids a
-     temporary and a loop.  */
-  if (!lhs_is_coindexed && rhs_is_coindexed
-      && (!lhs_caf_attr.codimension
-         || !(lhs_expr->rank > 0
-              && (lhs_caf_attr.allocatable || lhs_caf_attr.pointer))))
-    {
-      bool lhs_may_realloc = lhs_expr->rank > 0 && lhs_caf_attr.allocatable;
-      gfc_init_se (&rhs_se, NULL);
-      if (lhs_expr->rank == 0 && lhs_caf_attr.allocatable)
-       {
-         gfc_se scal_se;
-         gfc_init_se (&scal_se, NULL);
-         scal_se.want_pointer = 1;
-         gfc_conv_expr (&scal_se, lhs_expr);
-         /* Ensure scalar on lhs is allocated.  */
-         gfc_add_block_to_block (&block, &scal_se.pre);
-
-         gfc_allocate_using_malloc (&scal_se.pre, scal_se.expr,
-                                   TYPE_SIZE_UNIT (
-                                      gfc_typenode_for_spec (&lhs_expr->ts)),
-                                   NULL_TREE);
-         tmp = fold_build2 (EQ_EXPR, logical_type_node, scal_se.expr,
-                            null_pointer_node);
-         tmp = fold_build3_loc (input_location, COND_EXPR, void_type_node,
-                                tmp, gfc_finish_block (&scal_se.pre),
-                                build_empty_stmt (input_location));
-         gfc_add_expr_to_block (&block, tmp);
-       }
-      else
-       lhs_may_realloc = lhs_may_realloc
-           && gfc_full_array_ref_p (lhs_expr->ref, NULL);
+      gfc_conv_expr_descriptor (&lhs_se, lhs_expr);
       gfc_add_block_to_block (&block, &lhs_se.pre);
-      gfc_conv_intrinsic_caf_get (&rhs_se, code->ext.actual->next->expr,
-                                 lhs_se.expr, lhs_may_realloc, &rhs_caf_attr);
-      gfc_add_block_to_block (&block, &rhs_se.pre);
-      gfc_add_block_to_block (&block, &rhs_se.post);
-      gfc_add_block_to_block (&block, &lhs_se.post);
-      return gfc_finish_block (&block);
+      opt_lhs_desc = lhs_se.expr;
+      if (lhs_expr->ts.type == BT_CHARACTER)
+       opt_lhs_charlen = gfc_build_addr_expr (
+         NULL_TREE, gfc_trans_force_lval (&block, lhs_se.string_length));
+      else
+       opt_lhs_charlen = build_zero_cst (build_pointer_type (size_type_node));
+      if (!TYPE_LANG_SPECIFIC (TREE_TYPE (lhs_caf_decl))->rank
+         || GFC_ARRAY_TYPE_P (TREE_TYPE (lhs_caf_decl)))
+       opt_lhs_desc = null_pointer_node;
+      else
+       opt_lhs_desc
+         = gfc_build_addr_expr (NULL_TREE,
+                                gfc_trans_force_lval (&block, opt_lhs_desc));
     }
 
-  gfc_add_block_to_block (&block, &lhs_se.pre);
-
   /* Obtain token, offset and image index for the LHS.  */
-  caf_decl = gfc_get_tree_for_caf_expr (lhs_expr);
-  if (TREE_CODE (TREE_TYPE (caf_decl)) == REFERENCE_TYPE)
-    caf_decl = build_fold_indirect_ref_loc (input_location, caf_decl);
-  image_index = gfc_caf_get_image_index (&block, lhs_expr, caf_decl);
-  tmp = lhs_se.expr;
-  if (lhs_caf_attr.alloc_comp)
-    gfc_get_caf_token_offset (&lhs_se, &token, NULL, caf_decl, NULL_TREE,
-                             NULL);
-  else
-    gfc_get_caf_token_offset (&lhs_se, &token, &offset, caf_decl, tmp,
-                             lhs_expr);
-  lhs_se.expr = tmp;
+  lhs_image_index = gfc_caf_get_image_index (&block, lhs_expr, lhs_caf_decl);
+  gfc_get_caf_token_offset (&lhs_se, &lhs_token, NULL, lhs_caf_decl, NULL,
+                           lhs_expr);
 
   /* RHS.  */
+  rhs_caf_decl = gfc_get_tree_for_caf_expr (rhs_expr);
+  if (TREE_CODE (TREE_TYPE (rhs_caf_decl)) == REFERENCE_TYPE)
+    rhs_caf_decl = build_fold_indirect_ref_loc (input_location, rhs_caf_decl);
+  transfer_rank = rhs_expr->rank;
+  gfc_expression_rank (rhs_expr);
   gfc_init_se (&rhs_se, NULL);
-  if (rhs_expr->expr_type == EXPR_FUNCTION && rhs_expr->value.function.isym
-      && rhs_expr->value.function.isym->id == GFC_ISYM_CONVERSION)
-    rhs_expr = rhs_expr->value.function.actual->expr;
   if (rhs_expr->rank == 0)
     {
-      symbol_attribute attr;
-      gfc_clear_attr (&attr);
       gfc_conv_expr (&rhs_se, rhs_expr);
-      rhs_se.expr = gfc_conv_scalar_to_descriptor (&rhs_se, rhs_se.expr, attr);
-      rhs_se.expr = gfc_build_addr_expr (NULL_TREE, rhs_se.expr);
-    }
-  else if ((rhs_caf_attr.alloc_comp || rhs_caf_attr.pointer_comp)
-          && rhs_caf_attr.codimension)
-    {
-      tree tmp2;
-      rhs_se.want_pointer = 1;
-      gfc_conv_expr_descriptor (&rhs_se, rhs_expr);
-      /* Using gfc_conv_expr_descriptor, we only get the descriptor, but that
-        has the wrong type if component references are done.  */
-      tmp2 = gfc_typenode_for_spec (&rhs_expr->ts);
-      tmp = build_fold_indirect_ref_loc (input_location, rhs_se.expr);
-      gfc_add_modify (&rhs_se.pre, gfc_conv_descriptor_dtype (tmp),
-                     gfc_get_dtype_rank_type (
-                       gfc_has_vector_subscript (rhs_expr)
-                       ? gfc_find_array_ref (rhs_expr)->dimen
-                       : rhs_expr->rank,
-                     tmp2));
-    }
-  else
-    {
-      /* If has_vector, pass descriptor for whole array and the
-         vector bounds separately.  */
-      gfc_array_ref *ar, ar2;
-      bool has_vector = false;
-      tree tmp2;
-
-      if (rhs_is_coindexed && gfc_has_vector_subscript (rhs_expr))
+      gfc_add_block_to_block (&block, &rhs_se.pre);
+      opt_rhs_desc = null_pointer_node;
+      if (rhs_expr->ts.type == BT_CHARACTER)
        {
-          has_vector = true;
-          ar = gfc_find_array_ref (rhs_expr);
-         ar2 = *ar;
-         memset (ar, '\0', sizeof (*ar));
-         ar->as = ar2.as;
-         ar->type = AR_FULL;
+         opt_rhs_charlen = gfc_build_addr_expr (
+           NULL_TREE, gfc_trans_force_lval (&block, rhs_se.string_length));
+         rhs_size = build_int_cstu (size_type_node, rhs_expr->ts.kind);
        }
-      rhs_se.want_pointer = 1;
-      gfc_conv_expr_descriptor (&rhs_se, rhs_expr);
-      /* Using gfc_conv_expr_descriptor, we only get the descriptor, but that
-         has the wrong type if component references are done.  */
-      tmp = build_fold_indirect_ref_loc (input_location, rhs_se.expr);
-      tmp2 = gfc_typenode_for_spec (&rhs_expr->ts);
-      gfc_add_modify (&rhs_se.pre, gfc_conv_descriptor_dtype (tmp),
-                      gfc_get_dtype_rank_type (has_vector ? ar2.dimen
-                                                         : rhs_expr->rank,
-                     tmp2));
-      if (has_vector)
-       {
-         rhs_vec = conv_caf_vector_subscript (&block, rhs_se.expr, &ar2);
-         *ar = ar2;
+      else
+       {
+         opt_rhs_charlen
+           = build_zero_cst (build_pointer_type (size_type_node));
+         rhs_size = TREE_TYPE (rhs_se.expr)->type_common.size_unit;
        }
     }
-
-  gfc_add_block_to_block (&block, &rhs_se.pre);
-
-  rhs_kind = build_int_cst (integer_type_node, rhs_expr->ts.kind);
-
-  tmp_stat = gfc_find_stat_co (lhs_expr);
-
-  if (tmp_stat)
-    {
-      gfc_se stat_se;
-      gfc_init_se (&stat_se, NULL);
-      gfc_conv_expr_reference (&stat_se, tmp_stat);
-      dst_stat = stat_se.expr;
-      gfc_add_block_to_block (&block, &stat_se.pre);
-      gfc_add_block_to_block (&block, &stat_se.post);
-    }
-
-  tmp_team = gfc_find_team_co (lhs_expr);
-
-  if (tmp_team)
-    {
-      gfc_se team_se;
-      gfc_init_se (&team_se, NULL);
-      gfc_conv_expr_reference (&team_se, tmp_team);
-      dst_team = team_se.expr;
-      gfc_add_block_to_block (&block, &team_se.pre);
-      gfc_add_block_to_block (&block, &team_se.post);
-    }
-
-  if (!rhs_is_coindexed)
+  else if (!TYPE_LANG_SPECIFIC (TREE_TYPE (rhs_caf_decl))->rank
+          || GFC_ARRAY_TYPE_P (TREE_TYPE (rhs_caf_decl)))
     {
-      if (lhs_caf_attr.alloc_comp || lhs_caf_attr.pointer_comp
-         || has_ref_after_cafref (lhs_expr))
+      rhs_se.data_not_needed = 1;
+      gfc_conv_expr_descriptor (&rhs_se, rhs_expr);
+      gfc_add_block_to_block (&block, &rhs_se.pre);
+      if (rhs_expr->ts.type == BT_CHARACTER)
        {
-         tree reference, dst_realloc;
-         reference = conv_expr_ref_to_caf_ref (&block, lhs_expr);
-         dst_realloc
-           = lhs_caf_attr.allocatable ? boolean_true_node : boolean_false_node;
-         tmp = build_call_expr_loc (input_location,
-                                    gfor_fndecl_caf_send_by_ref,
-                                    10, token, image_index, rhs_se.expr,
-                                    reference, lhs_kind, rhs_kind,
-                                    may_require_tmp, dst_realloc, src_stat,
-                                    build_int_cst (integer_type_node,
-                                                   lhs_expr->ts.type));
+         opt_rhs_charlen = gfc_build_addr_expr (
+           NULL_TREE, gfc_trans_force_lval (&block, rhs_se.string_length));
+         rhs_size = build_int_cstu (size_type_node, rhs_expr->ts.kind);
        }
       else
-       tmp = build_call_expr_loc (input_location, gfor_fndecl_caf_send, 11,
-                                  token, offset, image_index, lhs_se.expr, vec,
-                                  rhs_se.expr, lhs_kind, rhs_kind,
-                                  may_require_tmp, src_stat, dst_team);
+       {
+         opt_rhs_charlen
+           = build_zero_cst (build_pointer_type (size_type_node));
+         rhs_size = TREE_TYPE (rhs_se.expr)->type_common.size_unit;
+       }
+      opt_rhs_desc = null_pointer_node;
     }
   else
     {
-      tree rhs_token, rhs_offset, rhs_image_index;
-
-      /* It guarantees memory consistency within the same segment.  */
-      tmp = gfc_build_string_const (strlen ("memory") + 1, "memory");
-      tmp = build5_loc (input_location, ASM_EXPR, void_type_node,
-                         gfc_build_string_const (1, ""), NULL_TREE, NULL_TREE,
-                         tree_cons (NULL_TREE, tmp, NULL_TREE), NULL_TREE);
-      ASM_VOLATILE_P (tmp) = 1;
-      gfc_add_expr_to_block (&block, tmp);
-
-      caf_decl = gfc_get_tree_for_caf_expr (rhs_expr);
-      if (TREE_CODE (TREE_TYPE (caf_decl)) == REFERENCE_TYPE)
-       caf_decl = build_fold_indirect_ref_loc (input_location, caf_decl);
-      rhs_image_index = gfc_caf_get_image_index (&block, rhs_expr, caf_decl);
-      tmp = rhs_se.expr;
-      if (rhs_caf_attr.alloc_comp || rhs_caf_attr.pointer_comp
-         || has_ref_after_cafref (lhs_expr))
+      gfc_ref *arr_ref = rhs_expr->ref;
+      while (arr_ref && arr_ref->type != REF_ARRAY)
+       arr_ref = arr_ref->next;
+      rhs_se.force_tmp
+       = (rhs_expr->shape == NULL
+          && (!arr_ref || !gfc_full_array_ref_p (arr_ref, nullptr)))
+         || !gfc_is_simply_contiguous (rhs_expr, false, false);
+      gfc_conv_expr_descriptor (&rhs_se, rhs_expr);
+      gfc_add_block_to_block (&block, &rhs_se.pre);
+      opt_rhs_desc = rhs_se.expr;
+      if (rhs_expr->ts.type == BT_CHARACTER)
        {
-         tmp_stat = gfc_find_stat_co (lhs_expr);
-
-         if (tmp_stat)
-           {
-             gfc_se stat_se;
-             gfc_init_se (&stat_se, NULL);
-             gfc_conv_expr_reference (&stat_se, tmp_stat);
-             src_stat = stat_se.expr;
-             gfc_add_block_to_block (&block, &stat_se.pre);
-             gfc_add_block_to_block (&block, &stat_se.post);
-           }
-
-         gfc_get_caf_token_offset (&rhs_se, &rhs_token, NULL, caf_decl,
-                                   NULL_TREE, NULL);
-         tree lhs_reference, rhs_reference;
-         lhs_reference = conv_expr_ref_to_caf_ref (&block, lhs_expr);
-         rhs_reference = conv_expr_ref_to_caf_ref (&block, rhs_expr);
-         tmp = build_call_expr_loc (input_location,
-                                    gfor_fndecl_caf_sendget_by_ref, 13,
-                                    token, image_index, lhs_reference,
-                                    rhs_token, rhs_image_index, rhs_reference,
-                                    lhs_kind, rhs_kind, may_require_tmp,
-                                    dst_stat, src_stat,
-                                    build_int_cst (integer_type_node,
-                                                   lhs_expr->ts.type),
-                                    build_int_cst (integer_type_node,
-                                                   rhs_expr->ts.type));
+         opt_rhs_charlen = gfc_build_addr_expr (
+           NULL_TREE, gfc_trans_force_lval (&block, rhs_se.string_length));
+         rhs_size = build_int_cstu (size_type_node, rhs_expr->ts.kind);
        }
       else
        {
-         gfc_get_caf_token_offset (&rhs_se, &rhs_token, &rhs_offset, caf_decl,
-                                   tmp, rhs_expr);
-         tmp = build_call_expr_loc (input_location, gfor_fndecl_caf_sendget,
-                                    14, token, offset, image_index,
-                                    lhs_se.expr, vec, rhs_token, rhs_offset,
-                                    rhs_image_index, tmp, rhs_vec, lhs_kind,
-                                    rhs_kind, may_require_tmp, src_stat);
+         opt_rhs_charlen
+           = build_zero_cst (build_pointer_type (size_type_node));
+         rhs_size = fold_build2 (
+           MULT_EXPR, size_type_node,
+           fold_convert (size_type_node,
+                         rhs_expr->shape
+                           ? conv_shape_to_cst (rhs_expr)
+                           : gfc_conv_descriptor_size (rhs_se.expr,
+                                                       rhs_expr->rank)),
+           fold_convert (size_type_node,
+                         gfc_conv_descriptor_span_get (rhs_se.expr)));
        }
+
+      opt_rhs_desc = gfc_build_addr_expr (NULL_TREE, opt_rhs_desc);
     }
+  gfc_add_block_to_block (&block, &rhs_se.pre);
+
+  /* Obtain token, offset and image index for the RHS.  */
+  rhs_image_index = gfc_caf_get_image_index (&block, rhs_expr, rhs_caf_decl);
+  gfc_get_caf_token_offset (&rhs_se, &rhs_token, NULL, rhs_caf_decl, NULL,
+                           rhs_expr);
+
+  /* stat and team.  */
+  conv_stat_and_team (&block, lhs_expr, &lhs_stat, &lhs_team);
+  conv_stat_and_team (&block, rhs_expr, &rhs_stat, &rhs_team);
+
+  sender_fn_index_tree
+    = conv_caf_func_index (&block, ns, "__caf_transfer_from_fn_index_%d",
+                          rhs_hash);
+  rhs_add_data_tree
+    = conv_caf_add_call_data (&block, ns,
+                             "__caf_transfer_from_remote_add_data_%d",
+                             rhs_add_data_sym, &rhs_add_data_size);
+  receiver_fn_index_tree
+    = conv_caf_func_index (&block, ns, "__caf_transfer_to_remote_fn_index_%d",
+                          lhs_hash);
+  lhs_add_data_tree
+    = conv_caf_add_call_data (&block, ns,
+                             "__caf_transfer_to_remote_add_data_%d",
+                             lhs_add_data_sym, &lhs_add_data_size);
+  ++caf_call_cnt;
+
+  tmp = build_call_expr_loc (
+    input_location, gfor_fndecl_caf_transfer_between_remotes, 20, lhs_token,
+    opt_lhs_desc, opt_lhs_charlen, lhs_image_index, receiver_fn_index_tree,
+    lhs_add_data_tree, lhs_add_data_size, rhs_token, opt_rhs_desc,
+    opt_rhs_charlen, rhs_image_index, sender_fn_index_tree, rhs_add_data_tree,
+    rhs_add_data_size, rhs_size,
+    transfer_rank == 0 ? boolean_true_node : boolean_false_node, lhs_stat,
+    lhs_team, null_pointer_node, rhs_stat, rhs_team, null_pointer_node);
+
   gfc_add_expr_to_block (&block, tmp);
   gfc_add_block_to_block (&block, &lhs_se.post);
   gfc_add_block_to_block (&block, &rhs_se.post);
@@ -2659,6 +2436,451 @@ conv_caf_sendget (gfc_code *code)
   return gfc_finish_block (&block);
 }
 
+// static tree
+// conv_caf_sendget (gfc_code *code)
+// {
+//   gfc_expr *lhs_expr, *rhs_expr, *tmp_stat, *tmp_team;
+//   gfc_se lhs_se, rhs_se;
+//   stmtblock_t block;
+//   tree caf_decl, token, offset, image_index, tmp, lhs_kind, rhs_kind;
+//   tree may_require_tmp, src_stat, dst_stat, dst_team;
+//   tree lhs_type = NULL_TREE;
+//   tree vec = null_pointer_node, rhs_vec = null_pointer_node;
+//   symbol_attribute lhs_caf_attr, rhs_caf_attr;
+//   bool lhs_is_coindexed, rhs_is_coindexed;
+
+//   gcc_assert (flag_coarray == GFC_FCOARRAY_LIB);
+
+//   lhs_expr
+//     = code->ext.actual->expr->expr_type == EXPR_FUNCTION
+//       && code->ext.actual->expr->value.function.isym->id == GFC_ISYM_CAF_GET
+//     ? code->ext.actual->expr->value.function.actual->expr
+//     : code->ext.actual->expr;
+//   rhs_expr = code->ext.actual->next->expr->expr_type == EXPR_FUNCTION
+//              && code->ext.actual->next->expr->value.function.isym->id
+//                   == GFC_ISYM_CAF_GET
+//            ? code->ext.actual->next->expr->value.function.actual->expr
+//            : code->ext.actual->next->expr;
+//   lhs_is_coindexed = gfc_is_coindexed (lhs_expr);
+//   rhs_is_coindexed = gfc_is_coindexed (rhs_expr);
+//   may_require_tmp = gfc_check_dependency (lhs_expr, rhs_expr, true) == 0
+//                 ? boolean_false_node : boolean_true_node;
+//   gfc_init_block (&block);
+
+//   lhs_caf_attr = gfc_caf_attr (lhs_expr);
+//   rhs_caf_attr = gfc_caf_attr (rhs_expr);
+//   src_stat = dst_stat = null_pointer_node;
+//   dst_team = null_pointer_node;
+
+//   /* LHS.  */
+//   gfc_init_se (&lhs_se, NULL);
+//   if (lhs_expr->rank == 0)
+//     {
+//       if (lhs_expr->ts.type == BT_CHARACTER && lhs_expr->ts.deferred)
+//     {
+//       lhs_se.expr = gfc_get_tree_for_caf_expr (lhs_expr);
+//       if (!POINTER_TYPE_P (TREE_TYPE (lhs_se.expr)))
+//         lhs_se.expr = gfc_build_addr_expr (NULL_TREE, lhs_se.expr);
+//     }
+//       else
+//     {
+//       symbol_attribute attr;
+//       gfc_clear_attr (&attr);
+//       gfc_conv_expr (&lhs_se, lhs_expr);
+//       lhs_type = TREE_TYPE (lhs_se.expr);
+//       if (lhs_is_coindexed)
+//         lhs_se.expr = gfc_conv_scalar_to_descriptor (&lhs_se, lhs_se.expr,
+//                                                      attr);
+//       lhs_se.expr = gfc_build_addr_expr (NULL_TREE, lhs_se.expr);
+//     }
+//     }
+//   else if ((lhs_caf_attr.alloc_comp || lhs_caf_attr.pointer_comp)
+//        && lhs_caf_attr.codimension)
+//     {
+//       lhs_se.want_pointer = 1;
+//       gfc_conv_expr_descriptor (&lhs_se, lhs_expr);
+//       /* Using gfc_conv_expr_descriptor, we only get the descriptor, but 
that
+//      has the wrong type if component references are done.  */
+//       lhs_type = gfc_typenode_for_spec (&lhs_expr->ts);
+//       tmp = build_fold_indirect_ref_loc (input_location, lhs_se.expr);
+//       gfc_add_modify (&lhs_se.pre, gfc_conv_descriptor_dtype (tmp),
+//                   gfc_get_dtype_rank_type (
+//                     gfc_has_vector_subscript (lhs_expr)
+//                     ? gfc_find_array_ref (lhs_expr)->dimen
+//                     : lhs_expr->rank,
+//                   lhs_type));
+//     }
+//   else
+//     {
+//       bool has_vector = gfc_has_vector_subscript (lhs_expr);
+
+//       if (lhs_is_coindexed || !has_vector)
+//     {
+//       /* If has_vector, pass descriptor for whole array and the
+//          vector bounds separately.  */
+//       gfc_array_ref *ar, ar2;
+//       bool has_tmp_lhs_array = false;
+//       if (has_vector)
+//         {
+//           has_tmp_lhs_array = true;
+//           ar = gfc_find_array_ref (lhs_expr);
+//           ar2 = *ar;
+//           memset (ar, '\0', sizeof (*ar));
+//           ar->as = ar2.as;
+//           ar->type = AR_FULL;
+//         }
+//       lhs_se.want_pointer = 1;
+//       gfc_conv_expr_descriptor (&lhs_se, lhs_expr);
+//       /* Using gfc_conv_expr_descriptor, we only get the descriptor, but
+//          that has the wrong type if component references are done.  */
+//       lhs_type = gfc_typenode_for_spec (&lhs_expr->ts);
+//       tmp = build_fold_indirect_ref_loc (input_location, lhs_se.expr);
+//       gfc_add_modify (&lhs_se.pre, gfc_conv_descriptor_dtype (tmp),
+//                       gfc_get_dtype_rank_type (has_vector ? ar2.dimen
+//                                                           : lhs_expr->rank,
+//                                                lhs_type));
+//       if (has_tmp_lhs_array)
+//         {
+//           vec = conv_caf_vector_subscript (&block, lhs_se.expr, &ar2);
+//           *ar = ar2;
+//         }
+//     }
+//       else if (rhs_is_coindexed)
+//     {
+//       /* Special casing for arr1 ([...]) = arr2[...], i.e. caf_get to
+//          indexed array expression.  This is rewritten to:
+
+//          tmp_array = arr2[...]
+//          arr1 ([...]) = tmp_array
+
+//          because using the standard gfc_conv_expr (lhs_expr) did the
+//          assignment with lhs and rhs exchanged.  */
+
+//       gfc_ss *lss_for_tmparray, *lss_real;
+//       gfc_loopinfo loop;
+//       gfc_se se;
+//       stmtblock_t body;
+//       tree tmparr_desc, src;
+//       tree index = gfc_index_zero_node;
+//       tree stride = gfc_index_zero_node;
+//       int n;
+
+//       /* Walk both sides of the assignment, once to get the shape of the
+//          temporary array to create right.  */
+//       lss_for_tmparray = gfc_walk_expr (lhs_expr);
+//       /* And a second time to be able to create an assignment of the
+//          temporary to the lhs_expr.  gfc_trans_create_temp_array replaces
+//          the tree in the descriptor with the one for the temporary
+//          array.  */
+//       lss_real = gfc_walk_expr (lhs_expr);
+//       gfc_init_loopinfo (&loop);
+//       gfc_add_ss_to_loop (&loop, lss_for_tmparray);
+//       gfc_add_ss_to_loop (&loop, lss_real);
+//       gfc_conv_ss_startstride (&loop);
+//       gfc_conv_loop_setup (&loop, &lhs_expr->where);
+//       lhs_type = gfc_typenode_for_spec (&lhs_expr->ts);
+//       gfc_trans_create_temp_array (&lhs_se.pre, &lhs_se.post,
+//                                    lss_for_tmparray, lhs_type, NULL_TREE,
+//                                    false, true, false,
+//                                    &lhs_expr->where);
+//       tmparr_desc = lss_for_tmparray->info->data.array.descriptor;
+//       gfc_start_scalarized_body (&loop, &body);
+//       gfc_init_se (&se, NULL);
+//       gfc_copy_loopinfo_to_se (&se, &loop);
+//       se.ss = lss_real;
+//       gfc_conv_expr (&se, lhs_expr);
+//       gfc_add_block_to_block (&body, &se.pre);
+
+//       /* Walk over all indexes of the loop.  */
+//       for (n = loop.dimen - 1; n > 0; --n)
+//         {
+//           tmp = loop.loopvar[n];
+//           tmp = fold_build2_loc (input_location, MINUS_EXPR,
+//                                  gfc_array_index_type, tmp, loop.from[n]);
+//           tmp = fold_build2_loc (input_location, PLUS_EXPR,
+//                                  gfc_array_index_type, tmp, index);
+
+//           stride = fold_build2_loc (input_location, MINUS_EXPR,
+//                                     gfc_array_index_type,
+//                                     loop.to[n - 1], loop.from[n - 1]);
+//           stride = fold_build2_loc (input_location, PLUS_EXPR,
+//                                     gfc_array_index_type,
+//                                     stride, gfc_index_one_node);
+
+//           index = fold_build2_loc (input_location, MULT_EXPR,
+//                                    gfc_array_index_type, tmp, stride);
+//         }
+
+//       index = fold_build2_loc (input_location, MINUS_EXPR,
+//                                gfc_array_index_type,
+//                                index, loop.from[0]);
+
+//       index = fold_build2_loc (input_location, PLUS_EXPR,
+//                                gfc_array_index_type,
+//                                loop.loopvar[0], index);
+
+//       src = build_fold_indirect_ref (gfc_conv_array_data (tmparr_desc));
+//       src = gfc_build_array_ref (src, index, NULL);
+//       /* Now create the assignment of lhs_expr = tmp_array.  */
+//       gfc_add_modify (&body, se.expr, src);
+//       gfc_add_block_to_block (&body, &se.post);
+//       lhs_se.expr = gfc_build_addr_expr (NULL_TREE, tmparr_desc);
+//       gfc_trans_scalarizing_loops (&loop, &body);
+//       gfc_add_block_to_block (&loop.pre, &loop.post);
+//       gfc_add_expr_to_block (&lhs_se.post, gfc_finish_block (&loop.pre));
+//       gfc_free_ss (lss_for_tmparray);
+//       gfc_free_ss (lss_real);
+//     }
+//     }
+
+//   lhs_kind = build_int_cst (integer_type_node, lhs_expr->ts.kind);
+
+//   /* Special case: RHS is a coarray but LHS is not; this code path avoids a
+//      temporary and a loop.  */
+//   if (!lhs_is_coindexed && rhs_is_coindexed
+//       && (!lhs_caf_attr.codimension
+//       || !(lhs_expr->rank > 0
+//            && (lhs_caf_attr.allocatable || lhs_caf_attr.pointer))))
+//     {
+//       bool lhs_may_realloc = lhs_expr->rank > 0 && lhs_caf_attr.allocatable;
+//       gfc_init_se (&rhs_se, NULL);
+//       if (lhs_expr->rank == 0 && lhs_caf_attr.allocatable)
+//     {
+//       gfc_se scal_se;
+//       gfc_init_se (&scal_se, NULL);
+//       scal_se.want_pointer = 1;
+//       gfc_conv_expr (&scal_se, lhs_expr);
+//       /* Ensure scalar on lhs is allocated.  */
+//       gfc_add_block_to_block (&block, &scal_se.pre);
+
+//       gfc_allocate_using_malloc (&scal_se.pre, scal_se.expr,
+//                                 TYPE_SIZE_UNIT (
+//                                    gfc_typenode_for_spec (&lhs_expr->ts)),
+//                                 NULL_TREE);
+//       tmp = fold_build2 (EQ_EXPR, logical_type_node, scal_se.expr,
+//                          null_pointer_node);
+//       tmp = fold_build3_loc (input_location, COND_EXPR, void_type_node,
+//                              tmp, gfc_finish_block (&scal_se.pre),
+//                              build_empty_stmt (input_location));
+//       gfc_add_expr_to_block (&block, tmp);
+//     }
+//       else
+//     lhs_may_realloc = lhs_may_realloc
+//         && gfc_full_array_ref_p (lhs_expr->ref, NULL);
+//       gfc_add_block_to_block (&block, &lhs_se.pre);
+//       gfc_conv_intrinsic_caf_get (&rhs_se, code->ext.actual->next->expr,
+//                               lhs_se.expr, lhs_may_realloc, &rhs_caf_attr);
+//       gfc_add_block_to_block (&block, &rhs_se.pre);
+//       gfc_add_block_to_block (&block, &rhs_se.post);
+//       gfc_add_block_to_block (&block, &lhs_se.post);
+//       return gfc_finish_block (&block);
+//     }
+
+//   gfc_add_block_to_block (&block, &lhs_se.pre);
+
+//   /* Obtain token, offset and image index for the LHS.  */
+//   caf_decl = gfc_get_tree_for_caf_expr (lhs_expr);
+//   if (TREE_CODE (TREE_TYPE (caf_decl)) == REFERENCE_TYPE)
+//     caf_decl = build_fold_indirect_ref_loc (input_location, caf_decl);
+//   image_index = gfc_caf_get_image_index (&block, lhs_expr, caf_decl);
+//   tmp = lhs_se.expr;
+//   if (lhs_caf_attr.alloc_comp)
+//     gfc_get_caf_token_offset (&lhs_se, &token, NULL, caf_decl, NULL_TREE,
+//                           NULL);
+//   else
+//     gfc_get_caf_token_offset (&lhs_se, &token, &offset, caf_decl, tmp,
+//                           lhs_expr);
+//   lhs_se.expr = tmp;
+
+//   /* RHS.  */
+//   gfc_init_se (&rhs_se, NULL);
+//   if (rhs_expr->expr_type == EXPR_FUNCTION && rhs_expr->value.function.isym
+//       && rhs_expr->value.function.isym->id == GFC_ISYM_CONVERSION)
+//     rhs_expr = rhs_expr->value.function.actual->expr;
+//   if (rhs_expr->rank == 0)
+//     {
+//       symbol_attribute attr;
+//       gfc_clear_attr (&attr);
+//       gfc_conv_expr (&rhs_se, rhs_expr);
+//       rhs_se.expr = gfc_conv_scalar_to_descriptor (&rhs_se, rhs_se.expr,
+//       attr); rhs_se.expr = gfc_build_addr_expr (NULL_TREE, rhs_se.expr);
+//     }
+//   else if ((rhs_caf_attr.alloc_comp || rhs_caf_attr.pointer_comp)
+//        && rhs_caf_attr.codimension)
+//     {
+//       tree tmp2;
+//       rhs_se.want_pointer = 1;
+//       gfc_conv_expr_descriptor (&rhs_se, rhs_expr);
+//       /* Using gfc_conv_expr_descriptor, we only get the descriptor, but 
that
+//      has the wrong type if component references are done.  */
+//       tmp2 = gfc_typenode_for_spec (&rhs_expr->ts);
+//       tmp = build_fold_indirect_ref_loc (input_location, rhs_se.expr);
+//       gfc_add_modify (&rhs_se.pre, gfc_conv_descriptor_dtype (tmp),
+//                   gfc_get_dtype_rank_type (
+//                     gfc_has_vector_subscript (rhs_expr)
+//                     ? gfc_find_array_ref (rhs_expr)->dimen
+//                     : rhs_expr->rank,
+//                   tmp2));
+//     }
+//   else
+//     {
+//       /* If has_vector, pass descriptor for whole array and the
+//          vector bounds separately.  */
+//       gfc_array_ref *ar, ar2;
+//       bool has_vector = false;
+//       tree tmp2;
+
+//       if (rhs_is_coindexed && gfc_has_vector_subscript (rhs_expr))
+//     {
+//           has_vector = true;
+//           ar = gfc_find_array_ref (rhs_expr);
+//       ar2 = *ar;
+//       memset (ar, '\0', sizeof (*ar));
+//       ar->as = ar2.as;
+//       ar->type = AR_FULL;
+//     }
+//       rhs_se.want_pointer = 1;
+//       gfc_conv_expr_descriptor (&rhs_se, rhs_expr);
+//       /* Using gfc_conv_expr_descriptor, we only get the descriptor, but 
that
+//          has the wrong type if component references are done.  */
+//       tmp = build_fold_indirect_ref_loc (input_location, rhs_se.expr);
+//       tmp2 = gfc_typenode_for_spec (&rhs_expr->ts);
+//       gfc_add_modify (&rhs_se.pre, gfc_conv_descriptor_dtype (tmp),
+//                       gfc_get_dtype_rank_type (has_vector ? ar2.dimen
+//                                                       : rhs_expr->rank,
+//                   tmp2));
+//       if (has_vector)
+//     {
+//       rhs_vec = conv_caf_vector_subscript (&block, rhs_se.expr, &ar2);
+//       *ar = ar2;
+//     }
+//     }
+
+//   gfc_add_block_to_block (&block, &rhs_se.pre);
+
+//   rhs_kind = build_int_cst (integer_type_node, rhs_expr->ts.kind);
+
+//   tmp_stat = gfc_find_stat_co (lhs_expr);
+
+//   if (tmp_stat)
+//     {
+//       gfc_se stat_se;
+//       gfc_init_se (&stat_se, NULL);
+//       gfc_conv_expr_reference (&stat_se, tmp_stat);
+//       dst_stat = stat_se.expr;
+//       gfc_add_block_to_block (&block, &stat_se.pre);
+//       gfc_add_block_to_block (&block, &stat_se.post);
+//     }
+
+//   tmp_team = gfc_find_team_co (lhs_expr);
+
+//   if (tmp_team)
+//     {
+//       gfc_se team_se;
+//       gfc_init_se (&team_se, NULL);
+//       gfc_conv_expr_reference (&team_se, tmp_team);
+//       dst_team = team_se.expr;
+//       gfc_add_block_to_block (&block, &team_se.pre);
+//       gfc_add_block_to_block (&block, &team_se.post);
+//     }
+
+//   if (!rhs_is_coindexed)
+//     {
+//       if (lhs_caf_attr.alloc_comp || lhs_caf_attr.pointer_comp
+//       || has_ref_after_cafref (lhs_expr))
+//     {
+//       tree reference, dst_realloc;
+//       reference = conv_expr_ref_to_caf_ref (&block, lhs_expr);
+//       dst_realloc
+//         = lhs_caf_attr.allocatable ? boolean_true_node : boolean_false_node;
+//       tmp = build_call_expr_loc (input_location,
+//                                  gfor_fndecl_caf_send_by_ref,
+//                                  10, token, image_index, rhs_se.expr,
+//                                  reference, lhs_kind, rhs_kind,
+//                                  may_require_tmp, dst_realloc, src_stat,
+//                                  build_int_cst (integer_type_node,
+//                                                 lhs_expr->ts.type));
+//     }
+//       else
+//     tmp = build_call_expr_loc (input_location, gfor_fndecl_caf_send, 11,
+//                                token, offset, image_index, lhs_se.expr, vec,
+//                                rhs_se.expr, lhs_kind, rhs_kind,
+//                                may_require_tmp, src_stat, dst_team);
+//     }
+//   else
+//     {
+//       tree rhs_token, rhs_offset, rhs_image_index;
+
+//       /* It guarantees memory consistency within the same segment.  */
+//       tmp = gfc_build_string_const (strlen ("memory") + 1, "memory");
+//       tmp = build5_loc (input_location, ASM_EXPR, void_type_node,
+//                       gfc_build_string_const (1, ""), NULL_TREE, NULL_TREE,
+//                       tree_cons (NULL_TREE, tmp, NULL_TREE), NULL_TREE);
+//       ASM_VOLATILE_P (tmp) = 1;
+//       gfc_add_expr_to_block (&block, tmp);
+
+//       caf_decl = gfc_get_tree_for_caf_expr (rhs_expr);
+//       if (TREE_CODE (TREE_TYPE (caf_decl)) == REFERENCE_TYPE)
+//     caf_decl = build_fold_indirect_ref_loc (input_location, caf_decl);
+//       rhs_image_index = gfc_caf_get_image_index (&block, rhs_expr, 
caf_decl);
+//       tmp = rhs_se.expr;
+//       if (rhs_caf_attr.alloc_comp || rhs_caf_attr.pointer_comp
+//       || has_ref_after_cafref (lhs_expr))
+//     {
+//       tmp_stat = gfc_find_stat_co (lhs_expr);
+
+//       if (tmp_stat)
+//         {
+//           gfc_se stat_se;
+//           gfc_init_se (&stat_se, NULL);
+//           gfc_conv_expr_reference (&stat_se, tmp_stat);
+//           src_stat = stat_se.expr;
+//           gfc_add_block_to_block (&block, &stat_se.pre);
+//           gfc_add_block_to_block (&block, &stat_se.post);
+//         }
+
+//       gfc_get_caf_token_offset (&rhs_se, &rhs_token, NULL, caf_decl,
+//                                 NULL_TREE, NULL);
+//       tree lhs_reference, rhs_reference;
+//       lhs_reference = conv_expr_ref_to_caf_ref (&block, lhs_expr);
+//       rhs_reference = conv_expr_ref_to_caf_ref (&block, rhs_expr);
+//       tmp = build_call_expr_loc (input_location,
+//                                  gfor_fndecl_caf_sendget_by_ref, 13,
+//                                  token, image_index, lhs_reference,
+//                                  rhs_token, rhs_image_index, rhs_reference,
+//                                  lhs_kind, rhs_kind, may_require_tmp,
+//                                  dst_stat, src_stat,
+//                                  build_int_cst (integer_type_node,
+//                                                 lhs_expr->ts.type),
+//                                  build_int_cst (integer_type_node,
+//                                                 rhs_expr->ts.type));
+//     }
+//       else
+//     {
+//       gfc_get_caf_token_offset (&rhs_se, &rhs_token, &rhs_offset, caf_decl,
+//                                 tmp, rhs_expr);
+//       tmp = build_call_expr_loc (input_location, gfor_fndecl_caf_sendget,
+//                                  14, token, offset, image_index,
+//                                  lhs_se.expr, vec, rhs_token, rhs_offset,
+//                                  rhs_image_index, tmp, rhs_vec, lhs_kind,
+//                                  rhs_kind, may_require_tmp, src_stat);
+//     }
+//     }
+//   gfc_add_expr_to_block (&block, tmp);
+//   gfc_add_block_to_block (&block, &lhs_se.post);
+//   gfc_add_block_to_block (&block, &rhs_se.post);
+
+//   /* It guarantees memory consistency within the same segment.  */
+//   tmp = gfc_build_string_const (strlen ("memory") + 1, "memory");
+//   tmp = build5_loc (input_location, ASM_EXPR, void_type_node,
+//                 gfc_build_string_const (1, ""), NULL_TREE, NULL_TREE,
+//                 tree_cons (NULL_TREE, tmp, NULL_TREE), NULL_TREE);
+//   ASM_VOLATILE_P (tmp) = 1;
+//   gfc_add_expr_to_block (&block, tmp);
+
+//   return gfc_finish_block (&block);
+// }
+
 static void
 trans_this_image (gfc_se * se, gfc_expr *expr)
 {
diff --git a/gcc/fortran/trans.h b/gcc/fortran/trans.h
index 8b76a277c07c..fcb091a3cc6c 100644
--- a/gcc/fortran/trans.h
+++ b/gcc/fortran/trans.h
@@ -897,6 +897,7 @@ extern GTY(()) tree 
gfor_fndecl_caf_register_accessors_finish;
 extern GTY(()) tree gfor_fndecl_caf_get_remote_function_index;
 extern GTY(()) tree gfor_fndecl_caf_get_from_remote;
 extern GTY(()) tree gfor_fndecl_caf_send_to_remote;
+extern GTY(()) tree gfor_fndecl_caf_transfer_between_remotes;
 
 extern GTY(()) tree gfor_fndecl_caf_sync_all;
 extern GTY(()) tree gfor_fndecl_caf_sync_memory;
diff --git a/gcc/testsuite/gfortran.dg/coarray_lib_comm_1.f90 
b/gcc/testsuite/gfortran.dg/coarray_lib_comm_1.f90
index 56f2a6c5c7a2..9da15053290d 100644
--- a/gcc/testsuite/gfortran.dg/coarray_lib_comm_1.f90
+++ b/gcc/testsuite/gfortran.dg/coarray_lib_comm_1.f90
@@ -39,5 +39,7 @@ if (any (A-B /= 0)) STOP 4
 end
 
 ! { dg-final { scan-tree-dump-times "_gfortran_caf_get_from_remote" 4 
"original" } }
-! { dg-final { scan-tree-dump-times "_gfortran_caf_sendget 
\\\(caf_token.\[0-9\]+, \\\(integer\\\(kind=\[48\]\\\)\\\) parm.\[0-9\]+.data - 
\\\(integer\\\(kind=\[48\]\\\)\\\) a, 1, &parm.\[0-9\]+, 0B, 
caf_token.\[0-9\]+, \\\(integer\\\(kind=\[48\]\\\)\\\) parm.\[0-9\]+.data - 
\\\(integer\\\(kind=\[48\]\\\)\\\) a, 1, &parm.\[0-9\]+, 0B, 4, 4, 1, 0B\\\);" 
1 "original" } }
+! { dg-final { scan-tree-dump-times "_gfortran_caf_transfer_between_remotes" 1 
"original" } }
+! { dg-final { scan-tree-dump-not "_gfortran_caf_transfer_get" "original" } }
+! { dg-final { scan-tree-dump-not "_gfortran_caf_transfer_send" "original" } }
 
diff --git a/libgfortran/caf/libcaf.h b/libgfortran/caf/libcaf.h
index 0af1813bbd56..ef3dacfd8e76 100644
--- a/libgfortran/caf/libcaf.h
+++ b/libgfortran/caf/libcaf.h
@@ -261,6 +261,18 @@ void _gfortran_caf_send_to_remote (
   void *add_data, const size_t add_data_size, int *stat, caf_team_t *team,
   int *team_number);
 
+void _gfortran_caf_transfer_between_remotes (
+  caf_token_t dst_token, gfc_descriptor_t *opt_dst_desc,
+  size_t *opt_dst_charlen, const int dst_image_index,
+  const int dst_access_index, void *dst_add_data,
+  const size_t dst_add_data_size, caf_token_t src_token,
+  const gfc_descriptor_t *opt_src_desc, const size_t *opt_src_charlen,
+  const int src_image_index, const int src_access_index, void *src_add_data,
+  const size_t src_add_data_size, const size_t src_size,
+  const bool scalar_transfer, int *dst_stat, int *src_stat,
+  caf_team_t *dst_team, int *dst_team_number, caf_team_t *src_team,
+  int *src_team_number);
+
 void _gfortran_caf_atomic_define (caf_token_t, size_t, int, void *, int *,
                                  int, int);
 void _gfortran_caf_atomic_ref (caf_token_t, size_t, int, void *, int *,
diff --git a/libgfortran/caf/single.c b/libgfortran/caf/single.c
index 625e1a71148b..1f7a9022e39e 100644
--- a/libgfortran/caf/single.c
+++ b/libgfortran/caf/single.c
@@ -3023,6 +3023,75 @@ _gfortran_caf_send_to_remote (
                                                  opt_src_charlen);
 }
 
+void
+_gfortran_caf_transfer_between_remotes (
+  caf_token_t dst_token, gfc_descriptor_t *opt_dst_desc,
+  size_t *opt_dst_charlen, const int dst_image_index,
+  const int dst_access_index, void *dst_add_data,
+  const size_t dst_add_data_size __attribute__ ((unused)),
+  caf_token_t src_token, const gfc_descriptor_t *opt_src_desc,
+  const size_t *opt_src_charlen, const int src_image_index,
+  const int src_access_index, void *src_add_data,
+  const size_t src_add_data_size __attribute__ ((unused)),
+  const size_t src_size, const bool scalar_transfer, int *dst_stat,
+  int *src_stat, caf_team_t *dst_team __attribute__ ((unused)),
+  int *dst_team_number __attribute__ ((unused)),
+  caf_team_t *src_team __attribute__ ((unused)),
+  int *src_team_number __attribute__ ((unused)))
+{
+  caf_single_token_t src_single_token = TOKEN (src_token),
+                    dst_single_token = TOKEN (dst_token);
+  void *src_ptr
+    = opt_src_desc ? (void *) opt_src_desc : src_single_token->memptr;
+  int32_t free_buffer;
+  void *dst_ptr
+    = opt_dst_desc ? (void *) opt_dst_desc : dst_single_token->memptr;
+  void *transfer_ptr, *buffer;
+  GFC_FULL_ARRAY_DESCRIPTOR (GFC_MAX_DIMENSIONS, void) *transfer_desc = NULL;
+  struct caf_single_token cb_token;
+  cb_token.memptr = src_add_data;
+  cb_token.desc = NULL;
+  cb_token.owning_memory = false;
+
+  if (src_stat)
+    *src_stat = 0;
+
+  if (!scalar_transfer)
+    {
+      const size_t desc_size = sizeof (*transfer_desc);
+      transfer_desc = alloca (desc_size);
+      memset (transfer_desc, 0, desc_size);
+      transfer_ptr = transfer_desc;
+    }
+  else if (opt_dst_charlen)
+    transfer_ptr = alloca (*opt_dst_charlen * src_size);
+  else
+    {
+      buffer = NULL;
+      transfer_ptr = &buffer;
+    }
+
+  accessor_hash_table[src_access_index].u.getter (
+    src_add_data, &src_image_index, transfer_ptr, &free_buffer, src_ptr,
+    &cb_token, 0, opt_dst_charlen, opt_src_charlen);
+
+  if (dst_stat)
+    *dst_stat = 0;
+
+  if (scalar_transfer)
+    transfer_ptr = *(void **) transfer_ptr;
+
+  cb_token.memptr = dst_add_data;
+  accessor_hash_table[dst_access_index].u.receiver (dst_add_data,
+                                                   &dst_image_index, dst_ptr,
+                                                   transfer_ptr, &cb_token, 0,
+                                                   opt_dst_charlen,
+                                                   opt_src_charlen);
+
+  if (free_buffer)
+    free (transfer_desc ? transfer_desc->base_addr : transfer_ptr);
+}
+
 void
 _gfortran_caf_atomic_define (caf_token_t token, size_t offset,
                             int image_index __attribute__ ((unused)),

Reply via email to