Software: Apache. PHP/5.4.45 

uname -a: Linux webm056.cluster010.gra.hosting.ovh.net 5.15.167-ovh-vps-grsec-zfs-classid #1 SMP Tue
Sep 17 08:14:20 UTC 2024 x86_64
 

uid=243112(mycochar) gid=100(users) groups=100(users)  

Safe-mode: OFF (not secure)

/home/mycochar/www/image/photo/gcc-12.3.0/libgfortran/caf/   drwxr-xr-x
Free 0 B of 0 B (0%)
Your ip: 216.73.216.77 - Server ip: 213.186.33.19
Home    Back    Forward    UPDIR    Refresh    Search    Buffer    

[Enumerate]    [Encoder]    [Tools]    [Proc.]    [FTP Brute]    [Sec.]    [SQL]    [PHP-Code]    [Backdoor Host]    [Back-Connection]    [milw0rm it!]    [PHP-Proxy]    [Self remove]
    


Viewing file:     single.c (91.64 KB)      -rw-r--r--
Select action/file-type:
(+) | (+) | (+) | Code (+) | Session (+) | (+) | SDB (+) | (+) | (+) | (+) | (+) | (+) |
/* Single-image implementation of GNU Fortran Coarray Library
   Copyright (C) 2011-2022 Free Software Foundation, Inc.
   Contributed by Tobias Burnus <burnus@net-b.de>

This file is part of the GNU Fortran Coarray Runtime Library (libcaf).

Libcaf is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3, or (at your option)
any later version.

Libcaf is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

Under Section 7 of GPL version 3, you are granted additional
permissions described in the GCC Runtime Library Exception, version
3.1, as published by the Free Software Foundation.

You should have received a copy of the GNU General Public License and
a copy of the GCC Runtime Library Exception along with this program;
see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
<http://www.gnu.org/licenses/>.  */

#include "libcaf.h"
#include <stdio.h>  /* For fputs and fprintf.  */
#include <stdlib.h> /* For exit and malloc.  */
#include <string.h> /* For memcpy and memset.  */
#include <stdarg.h> /* For variadic arguments.  */
#include <stdint.h>
#include <assert.h>

/* Define GFC_CAF_CHECK to enable run-time checking.  */
/* #define GFC_CAF_CHECK  1  */

struct caf_single_token
{
  /* The pointer to the memory registered.  For arrays this is the data member
     in the descriptor.  For components it's the pure data pointer.  */
  void *memptr;
  /* The descriptor when this token is associated to an allocatable array.  */
  gfc_descriptor_t *desc;
  /* Set when the caf lib has allocated the memory in memptr and is responsible
     for freeing it on deregister.  */
  bool owning_memory;
};
typedef struct caf_single_token *caf_single_token_t;

#define TOKEN(X) ((caf_single_token_t) (X))
#define MEMTOK(X) ((caf_single_token_t) (X))->memptr

/* Single-image implementation of the CAF library.
   Note: For performance reasons -fcoarry=single should be used
   rather than this library.  */

/* Global variables.  */
caf_static_t *caf_static_list = NULL;

/* Keep in sync with mpi.c.  */
static void
caf_runtime_error (const char *message, ...)
{
  va_list ap;
  fprintf (stderr, "Fortran runtime error: ");
  va_start (ap, message);
  vfprintf (stderr, message, ap);
  va_end (ap);
  fprintf (stderr, "\n");

  /* FIXME: Shutdown the Fortran RTL to flush the buffer.  PR 43849.  */
  exit (EXIT_FAILURE);
}

/* Error handling is similar everytime.  */
static void
caf_internal_error (const char *msg, int *stat, char *errmsg,
            size_t errmsg_len, ...)
{
  va_list args;
  va_start (args, errmsg_len);
  if (stat)
    {
      *stat = 1;
      if (errmsg_len > 0)
    {
      int len = snprintf (errmsg, errmsg_len, msg, args);
      if (len >= 0 && errmsg_len > (size_t) len)
        memset (&errmsg[len], ' ', errmsg_len - len);
    }
      va_end (args);
      return;
    }
  else
    caf_runtime_error (msg, args);
  va_end (args);
}


void
_gfortran_caf_init (int *argc __attribute__ ((unused)),
            char ***argv __attribute__ ((unused)))
{
}


void
_gfortran_caf_finalize (void)
{
  while (caf_static_list != NULL)
    {
      caf_static_t *tmp = caf_static_list->prev;
      free (caf_static_list->token);
      free (caf_static_list);
      caf_static_list = tmp;
    }
}


int
_gfortran_caf_this_image (int distance __attribute__ ((unused)))
{
  return 1;
}


int
_gfortran_caf_num_images (int distance __attribute__ ((unused)),
              int failed __attribute__ ((unused)))
{
  return 1;
}


void
_gfortran_caf_register (size_t size, caf_register_t type, caf_token_t *token,
            gfc_descriptor_t *data, int *stat, char *errmsg,
            size_t errmsg_len)
{
  const char alloc_fail_msg[] = "Failed to allocate coarray";
  void *local;
  caf_single_token_t single_token;

  if (type == CAF_REGTYPE_LOCK_STATIC || type == CAF_REGTYPE_LOCK_ALLOC
      || type == CAF_REGTYPE_CRITICAL)
    local = calloc (size, sizeof (bool));
  else if (type == CAF_REGTYPE_EVENT_STATIC || type == CAF_REGTYPE_EVENT_ALLOC)
    /* In the event_(wait|post) function the counter for events is a uint32,
       so better allocate enough memory here.  */
    local = calloc (size, sizeof (uint32_t));
  else if (type == CAF_REGTYPE_COARRAY_ALLOC_REGISTER_ONLY)
    local = NULL;
  else
    local = malloc (size);

  if (type != CAF_REGTYPE_COARRAY_ALLOC_ALLOCATE_ONLY)
    *token = malloc (sizeof (struct caf_single_token));

  if (unlikely (*token == NULL
        || (local == NULL
            && type != CAF_REGTYPE_COARRAY_ALLOC_REGISTER_ONLY)))
    {
      /* Freeing the memory conditionally seems pointless, but
     caf_internal_error () may return, when a stat is given and then the
     memory may be lost.  */
      if (local)
    free (local);
      if (*token)
    free (*token);
      caf_internal_error (alloc_fail_msg, stat, errmsg, errmsg_len);
      return;
    }

  single_token = TOKEN (*token);
  single_token->memptr = local;
  single_token->owning_memory = type != CAF_REGTYPE_COARRAY_ALLOC_REGISTER_ONLY;
  single_token->desc = GFC_DESCRIPTOR_RANK (data) > 0 ? data : NULL;


  if (stat)
    *stat = 0;

  if (type == CAF_REGTYPE_COARRAY_STATIC || type == CAF_REGTYPE_LOCK_STATIC
      || type == CAF_REGTYPE_CRITICAL || type == CAF_REGTYPE_EVENT_STATIC
      || type == CAF_REGTYPE_EVENT_ALLOC)
    {
      caf_static_t *tmp = malloc (sizeof (caf_static_t));
      tmp->prev  = caf_static_list;
      tmp->token = *token;
      caf_static_list = tmp;
    }
  GFC_DESCRIPTOR_DATA (data) = local;
}


void
_gfortran_caf_deregister (caf_token_t *token, caf_deregister_t type, int *stat,
              char *errmsg __attribute__ ((unused)),
              size_t errmsg_len __attribute__ ((unused)))
{
  caf_single_token_t single_token = TOKEN (*token);

  if (single_token->owning_memory && single_token->memptr)
    free (single_token->memptr);

  if (type != CAF_DEREGTYPE_COARRAY_DEALLOCATE_ONLY)
    {
      free (TOKEN (*token));
      *token = NULL;
    }
  else
    {
      single_token->memptr = NULL;
      single_token->owning_memory = false;
    }

  if (stat)
    *stat = 0;
}


void
_gfortran_caf_sync_all (int *stat,
            char *errmsg __attribute__ ((unused)),
            size_t errmsg_len __attribute__ ((unused)))
{
  __asm__ __volatile__ ("":::"memory");
  if (stat)
    *stat = 0;
}


void
_gfortran_caf_sync_memory (int *stat,
               char *errmsg __attribute__ ((unused)),
               size_t errmsg_len __attribute__ ((unused)))
{
  __asm__ __volatile__ ("":::"memory");
  if (stat)
    *stat = 0;
}


void
_gfortran_caf_sync_images (int count __attribute__ ((unused)),
               int images[] __attribute__ ((unused)),
               int *stat,
               char *errmsg __attribute__ ((unused)),
               size_t errmsg_len __attribute__ ((unused)))
{
#ifdef GFC_CAF_CHECK
  int i;

  for (i = 0; i < count; i++)
    if (images[i] != 1)
      {
    fprintf (stderr, "COARRAY ERROR: Invalid image index %d to SYNC "
         "IMAGES", images[i]);
    exit (EXIT_FAILURE);
      }
#endif

  __asm__ __volatile__ ("":::"memory");
  if (stat)
    *stat = 0;
}


void
_gfortran_caf_stop_numeric(int stop_code, bool quiet)
{
  if (!quiet)
    fprintf (stderr, "STOP %d\n", stop_code);
  exit (0);
}


void
_gfortran_caf_stop_str(const char *string, size_t len, bool quiet)
{
  if (!quiet)
    {
      fputs ("STOP ", stderr);
      while (len--)
    fputc (*(string++), stderr);
      fputs ("\n", stderr);
    }
  exit (0);
}


void
_gfortran_caf_error_stop_str (const char *string, size_t len, bool quiet)
{
  if (!quiet)
    {
      fputs ("ERROR STOP ", stderr);
      while (len--)
    fputc (*(string++), stderr);
      fputs ("\n", stderr);
    }
  exit (1);
}


/* Reported that the program terminated because of a fail image issued.
   Because this is a single image library, nothing else than aborting the whole
   program can be done.  */

void _gfortran_caf_fail_image (void)
{
  fputs ("IMAGE FAILED!\n", stderr);
  exit (0);
}


/* Get the status of image IMAGE.  Because being the single image library all
   other images are reported to be stopped.  */

int _gfortran_caf_image_status (int image,
                caf_team_t * team __attribute__ ((unused)))
{
  if (image == 1)
    return 0;
  else
    return CAF_STAT_STOPPED_IMAGE;
}


/* Single image library.  There cannot be any failed images with only one
   image.  */

void
_gfortran_caf_failed_images (gfc_descriptor_t *array,
                 caf_team_t * team __attribute__ ((unused)),
                 int * kind)
{
  int local_kind = kind != NULL ? *kind : 4;

  array->base_addr = NULL;
  array->dtype.type = BT_INTEGER;
  array->dtype.elem_len = local_kind;
   /* Setting lower_bound higher then upper_bound is what the compiler does to
      indicate an empty array.  */
  array->dim[0].lower_bound = 0;
  array->dim[0]._ubound = -1;
  array->dim[0]._stride = 1;
  array->offset = 0;
}


/* With only one image available no other images can be stopped.  Therefore
   return an empty array.  */

void
_gfortran_caf_stopped_images (gfc_descriptor_t *array,
                  caf_team_t * team __attribute__ ((unused)),
                  int * kind)
{
  int local_kind = kind != NULL ? *kind : 4;

  array->base_addr = NULL;
  array->dtype.type =  BT_INTEGER;
  array->dtype.elem_len =  local_kind;
  /* Setting lower_bound higher then upper_bound is what the compiler does to
     indicate an empty array.  */
  array->dim[0].lower_bound = 0;
  array->dim[0]._ubound = -1;
  array->dim[0]._stride = 1;
  array->offset = 0;
}


void
_gfortran_caf_error_stop (int error, bool quiet)
{
  if (!quiet)
    fprintf (stderr, "ERROR STOP %d\n", error);
  exit (error);
}


void
_gfortran_caf_co_broadcast (gfc_descriptor_t *a __attribute__ ((unused)),
                int source_image __attribute__ ((unused)),
                int *stat, char *errmsg __attribute__ ((unused)),
                size_t errmsg_len __attribute__ ((unused)))
{
  if (stat)
    *stat = 0;
}

void
_gfortran_caf_co_sum (gfc_descriptor_t *a __attribute__ ((unused)),
              int result_image __attribute__ ((unused)),
              int *stat, char *errmsg __attribute__ ((unused)),
              size_t errmsg_len __attribute__ ((unused)))
{
  if (stat)
    *stat = 0;
}

void
_gfortran_caf_co_min (gfc_descriptor_t *a __attribute__ ((unused)),
              int result_image __attribute__ ((unused)),
              int *stat, char *errmsg __attribute__ ((unused)),
              int a_len __attribute__ ((unused)),
              size_t errmsg_len __attribute__ ((unused)))
{
  if (stat)
    *stat = 0;
}

void
_gfortran_caf_co_max (gfc_descriptor_t *a __attribute__ ((unused)),
              int result_image __attribute__ ((unused)),
              int *stat, char *errmsg __attribute__ ((unused)),
              int a_len __attribute__ ((unused)),
              size_t errmsg_len __attribute__ ((unused)))
{
  if (stat)
    *stat = 0;
}


void
_gfortran_caf_co_reduce (gfc_descriptor_t *a __attribute__ ((unused)),
                        void * (*opr) (void *, void *)
                               __attribute__ ((unused)),
                        int opr_flags __attribute__ ((unused)),
                        int result_image __attribute__ ((unused)),
                        int *stat, char *errmsg __attribute__ ((unused)),
                        int a_len __attribute__ ((unused)),
                        size_t errmsg_len __attribute__ ((unused)))
 {
   if (stat)
     *stat = 0;
 }


static void
assign_char4_from_char1 (size_t dst_size, size_t src_size, uint32_t *dst,
             unsigned char *src)
{
  size_t i, n;
  n = dst_size/4 > src_size ? src_size : dst_size/4;
  for (i = 0; i < n; ++i)
    dst[i] = (int32_t) src[i];
  for (; i < dst_size/4; ++i)
    dst[i] = (int32_t) ' ';
}


static void
assign_char1_from_char4 (size_t dst_size, size_t src_size, unsigned char *dst,
             uint32_t *src)
{
  size_t i, n;
  n = dst_size > src_size/4 ? src_size/4 : dst_size;
  for (i = 0; i < n; ++i)
    dst[i] = src[i] > UINT8_MAX ? (unsigned char) '?' : (unsigned char) src[i];
  if (dst_size > n)
    memset (&dst[n], ' ', dst_size - n);
}


static void
convert_type (void *dst, int dst_type, int dst_kind, void *src, int src_type,
          int src_kind, int *stat)
{
#ifdef HAVE_GFC_INTEGER_16
  typedef __int128 int128t;
#else
  typedef int64_t int128t;
#endif

#if defined(GFC_REAL_16_IS_LONG_DOUBLE)
  typedef long double real128t;
  typedef _Complex long double complex128t;
#elif defined(HAVE_GFC_REAL_16)
  typedef _Complex float __attribute__((mode(TC))) __complex128;
  typedef __float128 real128t;
  typedef __complex128 complex128t;
#elif defined(HAVE_GFC_REAL_10)
  typedef long double real128t;
  typedef long double complex128t;
#else
  typedef double real128t;
  typedef _Complex double complex128t;
#endif

  int128t int_val = 0;
  real128t real_val = 0;
  complex128t cmpx_val = 0;

  switch (src_type)
    {
    case BT_INTEGER:
      if (src_kind == 1)
    int_val = *(int8_t*) src;
      else if (src_kind == 2)
    int_val = *(int16_t*) src;
      else if (src_kind == 4)
    int_val = *(int32_t*) src;
      else if (src_kind == 8)
    int_val = *(int64_t*) src;
#ifdef HAVE_GFC_INTEGER_16
      else if (src_kind == 16)
    int_val = *(int128t*) src;
#endif
      else
    goto error;
      break;
    case BT_REAL:
      if (src_kind == 4)
    real_val = *(float*) src;
      else if (src_kind == 8)
    real_val = *(double*) src;
#ifdef HAVE_GFC_REAL_10
      else if (src_kind == 10)
    real_val = *(long double*) src;
#endif
#ifdef HAVE_GFC_REAL_16
      else if (src_kind == 16)
    real_val = *(real128t*) src;
#endif
      else
    goto error;
      break;
    case BT_COMPLEX:
      if (src_kind == 4)
    cmpx_val = *(_Complex float*) src;
      else if (src_kind == 8)
    cmpx_val = *(_Complex double*) src;
#ifdef HAVE_GFC_REAL_10
      else if (src_kind == 10)
    cmpx_val = *(_Complex long double*) src;
#endif
#ifdef HAVE_GFC_REAL_16
      else if (src_kind == 16)
    cmpx_val = *(complex128t*) src;
#endif
      else
    goto error;
      break;
    default:
      goto error;
    }

  switch (dst_type)
    {
    case BT_INTEGER:
      if (src_type == BT_INTEGER)
    {
      if (dst_kind == 1)
        *(int8_t*) dst = (int8_t) int_val;
      else if (dst_kind == 2)
        *(int16_t*) dst = (int16_t) int_val;
      else if (dst_kind == 4)
        *(int32_t*) dst = (int32_t) int_val;
      else if (dst_kind == 8)
        *(int64_t*) dst = (int64_t) int_val;
#ifdef HAVE_GFC_INTEGER_16
      else if (dst_kind == 16)
        *(int128t*) dst = (int128t) int_val;
#endif
      else
        goto error;
    }
      else if (src_type == BT_REAL)
    {
      if (dst_kind == 1)
        *(int8_t*) dst = (int8_t) real_val;
      else if (dst_kind == 2)
        *(int16_t*) dst = (int16_t) real_val;
      else if (dst_kind == 4)
        *(int32_t*) dst = (int32_t) real_val;
      else if (dst_kind == 8)
        *(int64_t*) dst = (int64_t) real_val;
#ifdef HAVE_GFC_INTEGER_16
      else if (dst_kind == 16)
        *(int128t*) dst = (int128t) real_val;
#endif
      else
        goto error;
    }
      else if (src_type == BT_COMPLEX)
    {
      if (dst_kind == 1)
        *(int8_t*) dst = (int8_t) cmpx_val;
      else if (dst_kind == 2)
        *(int16_t*) dst = (int16_t) cmpx_val;
      else if (dst_kind == 4)
        *(int32_t*) dst = (int32_t) cmpx_val;
      else if (dst_kind == 8)
        *(int64_t*) dst = (int64_t) cmpx_val;
#ifdef HAVE_GFC_INTEGER_16
      else if (dst_kind == 16)
        *(int128t*) dst = (int128t) cmpx_val;
#endif
      else
        goto error;
    }
      else
    goto error;
      return;
    case BT_REAL:
      if (src_type == BT_INTEGER)
    {
      if (dst_kind == 4)
        *(float*) dst = (float) int_val;
      else if (dst_kind == 8)
        *(double*) dst = (double) int_val;
#ifdef HAVE_GFC_REAL_10
      else if (dst_kind == 10)
        *(long double*) dst = (long double) int_val;
#endif
#ifdef HAVE_GFC_REAL_16
      else if (dst_kind == 16)
        *(real128t*) dst = (real128t) int_val;
#endif
      else
        goto error;
    }
      else if (src_type == BT_REAL)
    {
      if (dst_kind == 4)
        *(float*) dst = (float) real_val;
      else if (dst_kind == 8)
        *(double*) dst = (double) real_val;
#ifdef HAVE_GFC_REAL_10
      else if (dst_kind == 10)
        *(long double*) dst = (long double) real_val;
#endif
#ifdef HAVE_GFC_REAL_16
      else if (dst_kind == 16)
        *(real128t*) dst = (real128t) real_val;
#endif
      else
        goto error;
    }
      else if (src_type == BT_COMPLEX)
    {
      if (dst_kind == 4)
        *(float*) dst = (float) cmpx_val;
      else if (dst_kind == 8)
        *(double*) dst = (double) cmpx_val;
#ifdef HAVE_GFC_REAL_10
      else if (dst_kind == 10)
        *(long double*) dst = (long double) cmpx_val;
#endif
#ifdef HAVE_GFC_REAL_16
      else if (dst_kind == 16)
        *(real128t*) dst = (real128t) cmpx_val;
#endif
      else
        goto error;
    }
      return;
    case BT_COMPLEX:
      if (src_type == BT_INTEGER)
    {
      if (dst_kind == 4)
        *(_Complex float*) dst = (_Complex float) int_val;
      else if (dst_kind == 8)
        *(_Complex double*) dst = (_Complex double) int_val;
#ifdef HAVE_GFC_REAL_10
      else if (dst_kind == 10)
        *(_Complex long double*) dst = (_Complex long double) int_val;
#endif
#ifdef HAVE_GFC_REAL_16
      else if (dst_kind == 16)
        *(complex128t*) dst = (complex128t) int_val;
#endif
      else
        goto error;
    }
      else if (src_type == BT_REAL)
    {
      if (dst_kind == 4)
        *(_Complex float*) dst = (_Complex float) real_val;
      else if (dst_kind == 8)
        *(_Complex double*) dst = (_Complex double) real_val;
#ifdef HAVE_GFC_REAL_10
      else if (dst_kind == 10)
        *(_Complex long double*) dst = (_Complex long double) real_val;
#endif
#ifdef HAVE_GFC_REAL_16
      else if (dst_kind == 16)
        *(complex128t*) dst = (complex128t) real_val;
#endif
      else
        goto error;
    }
      else if (src_type == BT_COMPLEX)
    {
      if (dst_kind == 4)
        *(_Complex float*) dst = (_Complex float) cmpx_val;
      else if (dst_kind == 8)
        *(_Complex double*) dst = (_Complex double) cmpx_val;
#ifdef HAVE_GFC_REAL_10
      else if (dst_kind == 10)
        *(_Complex long double*) dst = (_Complex long double) cmpx_val;
#endif
#ifdef HAVE_GFC_REAL_16
      else if (dst_kind == 16)
        *(complex128t*) dst = (complex128t) cmpx_val;
#endif
      else
        goto error;
    }
      else
    goto error;
      return;
    default:
      goto error;
    }

error:
  fprintf (stderr, "libcaf_single RUNTIME ERROR: Cannot convert type %d kind "
       "%d to type %d kind %d\n", src_type, src_kind, dst_type, dst_kind);
  if (stat)
    *stat = 1;
  else
    abort ();
}


void
_gfortran_caf_get (caf_token_t token, size_t offset,
           int image_index __attribute__ ((unused)),
           gfc_descriptor_t *src,
           caf_vector_t *src_vector __attribute__ ((unused)),
           gfc_descriptor_t *dest, int src_kind, int dst_kind,
           bool may_require_tmp, int *stat)
{
  /* FIXME: Handle vector subscripts.  */
  size_t i, k, size;
  int j;
  int rank = GFC_DESCRIPTOR_RANK (dest);
  size_t src_size = GFC_DESCRIPTOR_SIZE (src);
  size_t dst_size = GFC_DESCRIPTOR_SIZE (dest);

  if (stat)
    *stat = 0;

  if (rank == 0)
    {
      void *sr = (void *) ((char *) MEMTOK (token) + offset);
      if (GFC_DESCRIPTOR_TYPE (dest) == GFC_DESCRIPTOR_TYPE (src)
      && dst_kind == src_kind)
    {
      memmove (GFC_DESCRIPTOR_DATA (dest), sr,
           dst_size > src_size ? src_size : dst_size);
      if (GFC_DESCRIPTOR_TYPE (dest) == BT_CHARACTER && dst_size > src_size)
        {
          if (dst_kind == 1)
        memset ((void*)(char*) GFC_DESCRIPTOR_DATA (dest) + src_size,
            ' ', dst_size - src_size);
          else /* dst_kind == 4.  */
        for (i = src_size/4; i < dst_size/4; i++)
          ((int32_t*) GFC_DESCRIPTOR_DATA (dest))[i] = (int32_t) ' ';
        }
    }
      else if (GFC_DESCRIPTOR_TYPE (dest) == BT_CHARACTER && dst_kind == 1)
    assign_char1_from_char4 (dst_size, src_size, GFC_DESCRIPTOR_DATA (dest),
                 sr);
      else if (GFC_DESCRIPTOR_TYPE (dest) == BT_CHARACTER)
    assign_char4_from_char1 (dst_size, src_size, GFC_DESCRIPTOR_DATA (dest),
                 sr);
      else
    convert_type (GFC_DESCRIPTOR_DATA (dest), GFC_DESCRIPTOR_TYPE (dest),
              dst_kind, sr, GFC_DESCRIPTOR_TYPE (src), src_kind, stat);
      return;
    }

  size = 1;
  for (j = 0; j < rank; j++)
    {
      ptrdiff_t dimextent = dest->dim[j]._ubound - dest->dim[j].lower_bound + 1;
      if (dimextent < 0)
    dimextent = 0;
      size *= dimextent;
    }

  if (size == 0)
    return;

  if (may_require_tmp)
    {
      ptrdiff_t array_offset_sr, array_offset_dst;
      void *tmp = malloc (size*src_size);

      array_offset_dst = 0;
      for (i = 0; i < size; i++)
    {
      ptrdiff_t array_offset_sr = 0;
      ptrdiff_t stride = 1;
      ptrdiff_t extent = 1;
      for (j = 0; j < GFC_DESCRIPTOR_RANK (src)-1; j++)
        {
          array_offset_sr += ((i / (extent*stride))
                  % (src->dim[j]._ubound
                    - src->dim[j].lower_bound + 1))
                 * src->dim[j]._stride;
          extent = (src->dim[j]._ubound - src->dim[j].lower_bound + 1);
          stride = src->dim[j]._stride;
        }
      array_offset_sr += (i / extent) * src->dim[rank-1]._stride;
      void *sr = (void *)((char *) MEMTOK (token) + offset
              + array_offset_sr*GFC_DESCRIPTOR_SIZE (src));
          memcpy ((void *) ((char *) tmp + array_offset_dst), sr, src_size);
          array_offset_dst += src_size;
    }

      array_offset_sr = 0;
      for (i = 0; i < size; i++)
    {
      ptrdiff_t array_offset_dst = 0;
      ptrdiff_t stride = 1;
      ptrdiff_t extent = 1;
      for (j = 0; j < rank-1; j++)
        {
          array_offset_dst += ((i / (extent*stride))
                   % (dest->dim[j]._ubound
                      - dest->dim[j].lower_bound + 1))
                  * dest->dim[j]._stride;
          extent = (dest->dim[j]._ubound - dest->dim[j].lower_bound + 1);
          stride = dest->dim[j]._stride;
        }
      array_offset_dst += (i / extent) * dest->dim[rank-1]._stride;
      void *dst = dest->base_addr
              + array_offset_dst*GFC_DESCRIPTOR_SIZE (dest);
          void *sr = tmp + array_offset_sr;

      if (GFC_DESCRIPTOR_TYPE (dest) == GFC_DESCRIPTOR_TYPE (src)
          && dst_kind == src_kind)
        {
          memmove (dst, sr, dst_size > src_size ? src_size : dst_size);
          if (GFC_DESCRIPTOR_TYPE (dest) == BT_CHARACTER
              && dst_size > src_size)
        {
          if (dst_kind == 1)
            memset ((void*)(char*) dst + src_size, ' ',
                dst_size-src_size);
          else /* dst_kind == 4.  */
            for (k = src_size/4; k < dst_size/4; k++)
              ((int32_t*) dst)[k] = (int32_t) ' ';
        }
        }
      else if (GFC_DESCRIPTOR_TYPE (dest) == BT_CHARACTER && dst_kind == 1)
        assign_char1_from_char4 (dst_size, src_size, dst, sr);
      else if (GFC_DESCRIPTOR_TYPE (dest) == BT_CHARACTER)
        assign_char4_from_char1 (dst_size, src_size, dst, sr);
      else
        convert_type (dst, GFC_DESCRIPTOR_TYPE (dest), dst_kind,
              sr, GFC_DESCRIPTOR_TYPE (src), src_kind, stat);
          array_offset_sr += src_size;
    }

      free (tmp);
      return;
    }

  for (i = 0; i < size; i++)
    {
      ptrdiff_t array_offset_dst = 0;
      ptrdiff_t stride = 1;
      ptrdiff_t extent = 1;
      for (j = 0; j < rank-1; j++)
    {
      array_offset_dst += ((i / (extent*stride))
                   % (dest->dim[j]._ubound
                  - dest->dim[j].lower_bound + 1))
                  * dest->dim[j]._stride;
      extent = (dest->dim[j]._ubound - dest->dim[j].lower_bound + 1);
          stride = dest->dim[j]._stride;
    }
      array_offset_dst += (i / extent) * dest->dim[rank-1]._stride;
      void *dst = dest->base_addr + array_offset_dst*GFC_DESCRIPTOR_SIZE (dest);

      ptrdiff_t array_offset_sr = 0;
      stride = 1;
      extent = 1;
      for (j = 0; j < GFC_DESCRIPTOR_RANK (src)-1; j++)
    {
      array_offset_sr += ((i / (extent*stride))
                   % (src->dim[j]._ubound
                  - src->dim[j].lower_bound + 1))
                  * src->dim[j]._stride;
      extent = (src->dim[j]._ubound - src->dim[j].lower_bound + 1);
      stride = src->dim[j]._stride;
    }
      array_offset_sr += (i / extent) * src->dim[rank-1]._stride;
      void *sr = (void *)((char *) MEMTOK (token) + offset
              + array_offset_sr*GFC_DESCRIPTOR_SIZE (src));

      if (GFC_DESCRIPTOR_TYPE (dest) == GFC_DESCRIPTOR_TYPE (src)
      && dst_kind == src_kind)
    {
      memmove (dst, sr, dst_size > src_size ? src_size : dst_size);
      if (GFC_DESCRIPTOR_TYPE (dest) == BT_CHARACTER && dst_size > src_size)
        {
          if (dst_kind == 1)
        memset ((void*)(char*) dst + src_size, ' ', dst_size-src_size);
          else /* dst_kind == 4.  */
        for (k = src_size/4; k < dst_size/4; k++)
          ((int32_t*) dst)[k] = (int32_t) ' ';
        }
    }
      else if (GFC_DESCRIPTOR_TYPE (dest) == BT_CHARACTER && dst_kind == 1)
    assign_char1_from_char4 (dst_size, src_size, dst, sr);
      else if (GFC_DESCRIPTOR_TYPE (dest) == BT_CHARACTER)
    assign_char4_from_char1 (dst_size, src_size, dst, sr);
      else
    convert_type (dst, GFC_DESCRIPTOR_TYPE (dest), dst_kind,
              sr, GFC_DESCRIPTOR_TYPE (src), src_kind, stat);
    }
}


void
_gfortran_caf_send (caf_token_t token, size_t offset,
            int image_index __attribute__ ((unused)),
            gfc_descriptor_t *dest,
            caf_vector_t *dst_vector __attribute__ ((unused)),
            gfc_descriptor_t *src, int dst_kind, int src_kind,
            bool may_require_tmp, int *stat)
{
  /* FIXME: Handle vector subscripts.  */
  size_t i, k, size;
  int j;
  int rank = GFC_DESCRIPTOR_RANK (dest);
  size_t src_size = GFC_DESCRIPTOR_SIZE (src);
  size_t dst_size = GFC_DESCRIPTOR_SIZE (dest);

  if (stat)
    *stat = 0;

  if (rank == 0)
    {
      void *dst = (void *) ((char *) MEMTOK (token) + offset);
      if (GFC_DESCRIPTOR_TYPE (dest) == GFC_DESCRIPTOR_TYPE (src)
      && dst_kind == src_kind)
    {
      memmove (dst, GFC_DESCRIPTOR_DATA (src),
           dst_size > src_size ? src_size : dst_size);
      if (GFC_DESCRIPTOR_TYPE (dest) == BT_CHARACTER && dst_size > src_size)
        {
          if (dst_kind == 1)
        memset ((void*)(char*) dst + src_size, ' ', dst_size-src_size);
          else /* dst_kind == 4.  */
        for (i = src_size/4; i < dst_size/4; i++)
          ((int32_t*) dst)[i] = (int32_t) ' ';
        }
    }
      else if (GFC_DESCRIPTOR_TYPE (dest) == BT_CHARACTER && dst_kind == 1)
    assign_char1_from_char4 (dst_size, src_size, dst,
                 GFC_DESCRIPTOR_DATA (src));
      else if (GFC_DESCRIPTOR_TYPE (dest) == BT_CHARACTER)
    assign_char4_from_char1 (dst_size, src_size, dst,
                 GFC_DESCRIPTOR_DATA (src));
      else
    convert_type (dst, GFC_DESCRIPTOR_TYPE (dest), dst_kind,
              GFC_DESCRIPTOR_DATA (src), GFC_DESCRIPTOR_TYPE (src),
              src_kind, stat);
      return;
    }

  size = 1;
  for (j = 0; j < rank; j++)
    {
      ptrdiff_t dimextent = dest->dim[j]._ubound - dest->dim[j].lower_bound + 1;
      if (dimextent < 0)
    dimextent = 0;
      size *= dimextent;
    }

  if (size == 0)
    return;

  if (may_require_tmp)
    {
      ptrdiff_t array_offset_sr, array_offset_dst;
      void *tmp;

      if (GFC_DESCRIPTOR_RANK (src) == 0)
    {
      tmp = malloc (src_size);
      memcpy (tmp, GFC_DESCRIPTOR_DATA (src), src_size);
    }
      else
    {
      tmp = malloc (size*src_size);
      array_offset_dst = 0;
      for (i = 0; i < size; i++)
        {
          ptrdiff_t array_offset_sr = 0;
          ptrdiff_t stride = 1;
          ptrdiff_t extent = 1;
          for (j = 0; j < GFC_DESCRIPTOR_RANK (src)-1; j++)
        {
          array_offset_sr += ((i / (extent*stride))
                      % (src->dim[j]._ubound
                     - src->dim[j].lower_bound + 1))
                     * src->dim[j]._stride;
          extent = (src->dim[j]._ubound - src->dim[j].lower_bound + 1);
          stride = src->dim[j]._stride;
        }
          array_offset_sr += (i / extent) * src->dim[rank-1]._stride;
          void *sr = (void *) ((char *) src->base_addr
                   + array_offset_sr*GFC_DESCRIPTOR_SIZE (src));
          memcpy ((void *) ((char *) tmp + array_offset_dst), sr, src_size);
          array_offset_dst += src_size;
        }
    }

      array_offset_sr = 0;
      for (i = 0; i < size; i++)
    {
      ptrdiff_t array_offset_dst = 0;
      ptrdiff_t stride = 1;
      ptrdiff_t extent = 1;
      for (j = 0; j < rank-1; j++)
        {
          array_offset_dst += ((i / (extent*stride))
                   % (dest->dim[j]._ubound
                      - dest->dim[j].lower_bound + 1))
                  * dest->dim[j]._stride;
      extent = (dest->dim[j]._ubound - dest->dim[j].lower_bound + 1);
          stride = dest->dim[j]._stride;
        }
      array_offset_dst += (i / extent) * dest->dim[rank-1]._stride;
      void *dst = (void *)((char *) MEMTOK (token) + offset
              + array_offset_dst*GFC_DESCRIPTOR_SIZE (dest));
          void *sr = tmp + array_offset_sr;
      if (GFC_DESCRIPTOR_TYPE (dest) == GFC_DESCRIPTOR_TYPE (src)
          && dst_kind == src_kind)
        {
          memmove (dst, sr,
               dst_size > src_size ? src_size : dst_size);
          if (GFC_DESCRIPTOR_TYPE (dest) == BT_CHARACTER
          && dst_size > src_size)
        {
          if (dst_kind == 1)
            memset ((void*)(char*) dst + src_size, ' ',
                dst_size-src_size);
          else /* dst_kind == 4.  */
            for (k = src_size/4; k < dst_size/4; k++)
              ((int32_t*) dst)[k] = (int32_t) ' ';
        }
        }
      else if (GFC_DESCRIPTOR_TYPE (dest) == BT_CHARACTER && dst_kind == 1)
        assign_char1_from_char4 (dst_size, src_size, dst, sr);
      else if (GFC_DESCRIPTOR_TYPE (dest) == BT_CHARACTER)
        assign_char4_from_char1 (dst_size, src_size, dst, sr);
      else
        convert_type (dst, GFC_DESCRIPTOR_TYPE (dest), dst_kind,
              sr, GFC_DESCRIPTOR_TYPE (src), src_kind, stat);
          if (GFC_DESCRIPTOR_RANK (src))
        array_offset_sr += src_size;
    }
      free (tmp);
      return;
    }

  for (i = 0; i < size; i++)
    {
      ptrdiff_t array_offset_dst = 0;
      ptrdiff_t stride = 1;
      ptrdiff_t extent = 1;
      for (j = 0; j < rank-1; j++)
    {
      array_offset_dst += ((i / (extent*stride))
                   % (dest->dim[j]._ubound
                  - dest->dim[j].lower_bound + 1))
                  * dest->dim[j]._stride;
      extent = (dest->dim[j]._ubound - dest->dim[j].lower_bound + 1);
          stride = dest->dim[j]._stride;
    }
      array_offset_dst += (i / extent) * dest->dim[rank-1]._stride;
      void *dst = (void *)((char *) MEMTOK (token) + offset
               + array_offset_dst*GFC_DESCRIPTOR_SIZE (dest));
      void *sr;
      if (GFC_DESCRIPTOR_RANK (src) != 0)
    {
      ptrdiff_t array_offset_sr = 0;
      stride = 1;
      extent = 1;
      for (j = 0; j < GFC_DESCRIPTOR_RANK (src)-1; j++)
        {
          array_offset_sr += ((i / (extent*stride))
                  % (src->dim[j]._ubound
                     - src->dim[j].lower_bound + 1))
                 * src->dim[j]._stride;
          extent = (src->dim[j]._ubound - src->dim[j].lower_bound + 1);
          stride = src->dim[j]._stride;
        }
      array_offset_sr += (i / extent) * src->dim[rank-1]._stride;
      sr = (void *)((char *) src->base_addr
            + array_offset_sr*GFC_DESCRIPTOR_SIZE (src));
    }
      else
    sr = src->base_addr;

      if (GFC_DESCRIPTOR_TYPE (dest) == GFC_DESCRIPTOR_TYPE (src)
      && dst_kind == src_kind)
    {
      memmove (dst, sr,
           dst_size > src_size ? src_size : dst_size);
      if (GFC_DESCRIPTOR_TYPE (dest) == BT_CHARACTER && dst_size > src_size)
        {
          if (dst_kind == 1)
        memset ((void*)(char*) dst + src_size, ' ', dst_size-src_size);
          else /* dst_kind == 4.  */
        for (k = src_size/4; k < dst_size/4; k++)
          ((int32_t*) dst)[k] = (int32_t) ' ';
        }
    }
      else if (GFC_DESCRIPTOR_TYPE (dest) == BT_CHARACTER && dst_kind == 1)
    assign_char1_from_char4 (dst_size, src_size, dst, sr);
      else if (GFC_DESCRIPTOR_TYPE (dest) == BT_CHARACTER)
    assign_char4_from_char1 (dst_size, src_size, dst, sr);
      else
    convert_type (dst, GFC_DESCRIPTOR_TYPE (dest), dst_kind,
              sr, GFC_DESCRIPTOR_TYPE (src), src_kind, stat);
    }
}


void
_gfortran_caf_sendget (caf_token_t dst_token, size_t dst_offset,
               int dst_image_index, gfc_descriptor_t *dest,
               caf_vector_t *dst_vector, caf_token_t src_token,
               size_t src_offset,
               int src_image_index __attribute__ ((unused)),
               gfc_descriptor_t *src,
               caf_vector_t *src_vector __attribute__ ((unused)),
               int dst_kind, int src_kind, bool may_require_tmp)
{
  /* FIXME: Handle vector subscript of 'src_vector'.  */
  /* For a single image, src->base_addr should be the same as src_token + offset
     but to play save, we do it properly.  */
  void *src_base = GFC_DESCRIPTOR_DATA (src);
  GFC_DESCRIPTOR_DATA (src) = (void *) ((char *) MEMTOK (src_token)
                    + src_offset);
  _gfortran_caf_send (dst_token, dst_offset, dst_image_index, dest, dst_vector,
              src, dst_kind, src_kind, may_require_tmp, NULL);
  GFC_DESCRIPTOR_DATA (src) = src_base;
}


/* Emitted when a theorectically unreachable part is reached.  */
const char unreachable[] = "Fatal error: unreachable alternative found.\n";


static void
copy_data (void *ds, void *sr, int dst_type, int src_type,
       int dst_kind, int src_kind, size_t dst_size, size_t src_size,
       size_t num, int *stat)
{
  size_t k;
  if (dst_type == src_type && dst_kind == src_kind)
    {
      memmove (ds, sr, (dst_size > src_size ? src_size : dst_size) * num);
      if ((dst_type == BT_CHARACTER || src_type == BT_CHARACTER)
      && dst_size > src_size)
    {
      if (dst_kind == 1)
        memset ((void*)(char*) ds + src_size, ' ', dst_size-src_size);
      else /* dst_kind == 4.  */
        for (k = src_size/4; k < dst_size/4; k++)
          ((int32_t*) ds)[k] = (int32_t) ' ';
    }
    }
  else if (dst_type == BT_CHARACTER && dst_kind == 1)
    assign_char1_from_char4 (dst_size, src_size, ds, sr);
  else if (dst_type == BT_CHARACTER)
    assign_char4_from_char1 (dst_size, src_size, ds, sr);
  else
    for (k = 0; k < num; ++k)
      {
    convert_type (ds, dst_type, dst_kind, sr, src_type, src_kind, stat);
    ds += dst_size;
    sr += src_size;
      }
}


#define COMPUTE_NUM_ITEMS(num, stride, lb, ub) \
  do { \
    index_type abs_stride = (stride) > 0 ? (stride) : -(stride); \
    num = (stride) > 0 ? (ub) + 1 - (lb) : (lb) + 1 - (ub); \
    if (num <= 0 || abs_stride < 1) return; \
    num = (abs_stride > 1) ? (1 + (num - 1) / abs_stride) : num; \
  } while (0)


static void
get_for_ref (caf_reference_t *ref, size_t *i, size_t *dst_index,
         caf_single_token_t single_token, gfc_descriptor_t *dst,
         gfc_descriptor_t *src, void *ds, void *sr,
         int dst_kind, int src_kind, size_t dst_dim, size_t src_dim,
         size_t num, int *stat, int src_type)
{
  ptrdiff_t extent_src = 1, array_offset_src = 0, stride_src;
  size_t next_dst_dim;

  if (unlikely (ref == NULL))
    /* May be we should issue an error here, because this case should not
       occur.  */
    return;

  if (ref->next == NULL)
    {
      size_t dst_size = GFC_DESCRIPTOR_SIZE (dst);
      ptrdiff_t array_offset_dst = 0;;
      size_t dst_rank = GFC_DESCRIPTOR_RANK (dst);

      switch (ref->type)
    {
    case CAF_REF_COMPONENT:
      /* Because the token is always registered after the component, its
         offset is always greater zero.  */
      if (ref->u.c.caf_token_offset > 0)
        /* Note, that sr is dereffed here.  */
        copy_data (ds, *(void **)(sr + ref->u.c.offset),
               GFC_DESCRIPTOR_TYPE (dst), src_type,
               dst_kind, src_kind, dst_size, ref->item_size, 1, stat);
      else
        copy_data (ds, sr + ref->u.c.offset,
               GFC_DESCRIPTOR_TYPE (dst), src_type,
               dst_kind, src_kind, dst_size, ref->item_size, 1, stat);
      ++(*i);
      return;
    case CAF_REF_STATIC_ARRAY:
      /* Intentionally fall through.  */
    case CAF_REF_ARRAY:
      if (ref->u.a.mode[src_dim] == CAF_ARR_REF_NONE)
        {
          for (size_t d = 0; d < dst_rank; ++d)
        array_offset_dst += dst_index[d];
          copy_data (ds + array_offset_dst * dst_size, sr,
             GFC_DESCRIPTOR_TYPE (dst), src_type,
             dst_kind, src_kind, dst_size, ref->item_size, num,
             stat);
          *i += num;
          return;
        }
      break;
    default:
      caf_runtime_error (unreachable);
    }
    }

  switch (ref->type)
    {
    case CAF_REF_COMPONENT:
      if (ref->u.c.caf_token_offset > 0)
    {
      single_token = *(caf_single_token_t*)(sr + ref->u.c.caf_token_offset);

      if (ref->next && ref->next->type == CAF_REF_ARRAY)
        src = single_token->desc;
      else
        src = NULL;

      if (ref->next && ref->next->type == CAF_REF_COMPONENT)
        /* The currently ref'ed component was allocatabe (caf_token_offset
           > 0) and the next ref is a component, too, then the new sr has to
           be dereffed.  (static arrays cannot be allocatable or they
           become an array with descriptor.  */
        sr = *(void **)(sr + ref->u.c.offset);
      else
        sr += ref->u.c.offset;

      get_for_ref (ref->next, i, dst_index, single_token, dst, src,
               ds, sr, dst_kind, src_kind, dst_dim, 0,
               1, stat, src_type);
    }
      else
    get_for_ref (ref->next, i, dst_index, single_token, dst,
             (gfc_descriptor_t *)(sr + ref->u.c.offset), ds,
             sr + ref->u.c.offset, dst_kind, src_kind, dst_dim, 0, 1,
             stat, src_type);
      return;
    case CAF_REF_ARRAY:
      if (ref->u.a.mode[src_dim] == CAF_ARR_REF_NONE)
    {
      get_for_ref (ref->next, i, dst_index, single_token, dst,
               src, ds, sr, dst_kind, src_kind,
               dst_dim, 0, 1, stat, src_type);
      return;
    }
      /* Only when on the left most index switch the data pointer to
     the array's data pointer.  */
      if (src_dim == 0)
    sr = GFC_DESCRIPTOR_DATA (src);
      switch (ref->u.a.mode[src_dim])
    {
    case CAF_ARR_REF_VECTOR:
      extent_src = GFC_DIMENSION_EXTENT (src->dim[src_dim]);
      array_offset_src = 0;
      dst_index[dst_dim] = 0;
      for (size_t idx = 0; idx < ref->u.a.dim[src_dim].v.nvec;
           ++idx)
        {
#define KINDCASE(kind, type) case kind: \
          array_offset_src = (((index_type) \
          ((type *)ref->u.a.dim[src_dim].v.vector)[idx]) \
          - GFC_DIMENSION_LBOUND (src->dim[src_dim])) \
          * GFC_DIMENSION_STRIDE (src->dim[src_dim]); \
          break

          switch (ref->u.a.dim[src_dim].v.kind)
        {
        KINDCASE (1, GFC_INTEGER_1);
        KINDCASE (2, GFC_INTEGER_2);
        KINDCASE (4, GFC_INTEGER_4);
#ifdef HAVE_GFC_INTEGER_8
        KINDCASE (8, GFC_INTEGER_8);
#endif
#ifdef HAVE_GFC_INTEGER_16
        KINDCASE (16, GFC_INTEGER_16);
#endif
        default:
          caf_runtime_error (unreachable);
          return;
        }
#undef KINDCASE

          get_for_ref (ref, i, dst_index, single_token, dst, src,
               ds, sr + array_offset_src * ref->item_size,
               dst_kind, src_kind, dst_dim + 1, src_dim + 1,
               1, stat, src_type);
          dst_index[dst_dim]
          += GFC_DIMENSION_STRIDE (dst->dim[dst_dim]);
        }
      return;
    case CAF_ARR_REF_FULL:
      COMPUTE_NUM_ITEMS (extent_src,
                 ref->u.a.dim[src_dim].s.stride,
                 GFC_DIMENSION_LBOUND (src->dim[src_dim]),
                 GFC_DIMENSION_UBOUND (src->dim[src_dim]));
      stride_src = src->dim[src_dim]._stride
          * ref->u.a.dim[src_dim].s.stride;
      array_offset_src = 0;
      dst_index[dst_dim] = 0;
      for (index_type idx = 0; idx < extent_src;
           ++idx, array_offset_src += stride_src)
        {
          get_for_ref (ref, i, dst_index, single_token, dst, src,
               ds, sr + array_offset_src * ref->item_size,
               dst_kind, src_kind, dst_dim + 1, src_dim + 1,
               1, stat, src_type);
          dst_index[dst_dim]
          += GFC_DIMENSION_STRIDE (dst->dim[dst_dim]);
        }
      return;
    case CAF_ARR_REF_RANGE:
      COMPUTE_NUM_ITEMS (extent_src,
                 ref->u.a.dim[src_dim].s.stride,
                 ref->u.a.dim[src_dim].s.start,
                 ref->u.a.dim[src_dim].s.end);
      array_offset_src = (ref->u.a.dim[src_dim].s.start
                  - GFC_DIMENSION_LBOUND (src->dim[src_dim]))
          * GFC_DIMENSION_STRIDE (src->dim[src_dim]);
      stride_src = GFC_DIMENSION_STRIDE (src->dim[src_dim])
          * ref->u.a.dim[src_dim].s.stride;
      dst_index[dst_dim] = 0;
      /* Increase the dst_dim only, when the src_extent is greater one
         or src and dst extent are both one.  Don't increase when the scalar
         source is not present in the dst.  */
      next_dst_dim = extent_src > 1
          || (GFC_DIMENSION_EXTENT (dst->dim[dst_dim]) == 1
          && extent_src == 1) ? (dst_dim + 1) : dst_dim;
      for (index_type idx = 0; idx < extent_src; ++idx)
        {
          get_for_ref (ref, i, dst_index, single_token, dst, src,
               ds, sr + array_offset_src * ref->item_size,
               dst_kind, src_kind, next_dst_dim, src_dim + 1,
               1, stat, src_type);
          dst_index[dst_dim]
          += GFC_DIMENSION_STRIDE (dst->dim[dst_dim]);
          array_offset_src += stride_src;
        }
      return;
    case CAF_ARR_REF_SINGLE:
      array_offset_src = (ref->u.a.dim[src_dim].s.start
                  - src->dim[src_dim].lower_bound)
          * GFC_DIMENSION_STRIDE (src->dim[src_dim]);
      dst_index[dst_dim] = 0;
      get_for_ref (ref, i, dst_index, single_token, dst, src, ds,
               sr + array_offset_src * ref->item_size,
               dst_kind, src_kind, dst_dim, src_dim + 1, 1,
               stat, src_type);
      return;
    case CAF_ARR_REF_OPEN_END:
      COMPUTE_NUM_ITEMS (extent_src,
                 ref->u.a.dim[src_dim].s.stride,
                 ref->u.a.dim[src_dim].s.start,
                 GFC_DIMENSION_UBOUND (src->dim[src_dim]));
      stride_src = GFC_DIMENSION_STRIDE (src->dim[src_dim])
          * ref->u.a.dim[src_dim].s.stride;
      array_offset_src = (ref->u.a.dim[src_dim].s.start
                  - GFC_DIMENSION_LBOUND (src->dim[src_dim]))
          * GFC_DIMENSION_STRIDE (src->dim[src_dim]);
      dst_index[dst_dim] = 0;
      for (index_type idx = 0; idx < extent_src; ++idx)
        {
          get_for_ref (ref, i, dst_index, single_token, dst, src,
               ds, sr + array_offset_src * ref->item_size,
               dst_kind, src_kind, dst_dim + 1, src_dim + 1,
               1, stat, src_type);
          dst_index[dst_dim]
          += GFC_DIMENSION_STRIDE (dst->dim[dst_dim]);
          array_offset_src += stride_src;
        }
      return;
    case CAF_ARR_REF_OPEN_START:
      COMPUTE_NUM_ITEMS (extent_src,
                 ref->u.a.dim[src_dim].s.stride,
                 GFC_DIMENSION_LBOUND (src->dim[src_dim]),
                 ref->u.a.dim[src_dim].s.end);
      stride_src = GFC_DIMENSION_STRIDE (src->dim[src_dim])
          * ref->u.a.dim[src_dim].s.stride;
      array_offset_src = 0;
      dst_index[dst_dim] = 0;
      for (index_type idx = 0; idx < extent_src; ++idx)
        {
          get_for_ref (ref, i, dst_index, single_token, dst, src,
               ds, sr + array_offset_src * ref->item_size,
               dst_kind, src_kind, dst_dim + 1, src_dim + 1,
               1, stat, src_type);
          dst_index[dst_dim]
          += GFC_DIMENSION_STRIDE (dst->dim[dst_dim]);
          array_offset_src += stride_src;
        }
      return;
    default:
      caf_runtime_error (unreachable);
    }
      return;
    case CAF_REF_STATIC_ARRAY:
      if (ref->u.a.mode[src_dim] == CAF_ARR_REF_NONE)
    {
      get_for_ref (ref->next, i, dst_index, single_token, dst,
               NULL, ds, sr, dst_kind, src_kind,
               dst_dim, 0, 1, stat, src_type);
      return;
    }
      switch (ref->u.a.mode[src_dim])
    {
    case CAF_ARR_REF_VECTOR:
      array_offset_src = 0;
      dst_index[dst_dim] = 0;
      for (size_t idx = 0; idx < ref->u.a.dim[src_dim].v.nvec;
           ++idx)
        {
#define KINDCASE(kind, type) case kind: \
         array_offset_src = ((type *)ref->u.a.dim[src_dim].v.vector)[idx]; \
          break

          switch (ref->u.a.dim[src_dim].v.kind)
        {
        KINDCASE (1, GFC_INTEGER_1);
        KINDCASE (2, GFC_INTEGER_2);
        KINDCASE (4, GFC_INTEGER_4);
#ifdef HAVE_GFC_INTEGER_8
        KINDCASE (8, GFC_INTEGER_8);
#endif
#ifdef HAVE_GFC_INTEGER_16
        KINDCASE (16, GFC_INTEGER_16);
#endif
        default:
          caf_runtime_error (unreachable);
          return;
        }
#undef KINDCASE

          get_for_ref (ref, i, dst_index, single_token, dst, NULL,
               ds, sr + array_offset_src * ref->item_size,
               dst_kind, src_kind, dst_dim + 1, src_dim + 1,
               1, stat, src_type);
          dst_index[dst_dim]
          += GFC_DIMENSION_STRIDE (dst->dim[dst_dim]);
        }
      return;
    case CAF_ARR_REF_FULL:
      dst_index[dst_dim] = 0;
      for (array_offset_src = 0 ;
           array_offset_src <= ref->u.a.dim[src_dim].s.end;
           array_offset_src += ref->u.a.dim[src_dim].s.stride)
        {
          get_for_ref (ref, i, dst_index, single_token, dst, NULL,
               ds, sr + array_offset_src * ref->item_size,
               dst_kind, src_kind, dst_dim + 1, src_dim + 1,
               1, stat, src_type);
          dst_index[dst_dim]
          += GFC_DIMENSION_STRIDE (dst->dim[dst_dim]);
        }
      return;
    case CAF_ARR_REF_RANGE:
      COMPUTE_NUM_ITEMS (extent_src,
                 ref->u.a.dim[src_dim].s.stride,
                 ref->u.a.dim[src_dim].s.start,
                 ref->u.a.dim[src_dim].s.end);
      array_offset_src = ref->u.a.dim[src_dim].s.start;
      dst_index[dst_dim] = 0;
      for (index_type idx = 0; idx < extent_src; ++idx)
        {
          get_for_ref (ref, i, dst_index, single_token, dst, NULL,
               ds, sr + array_offset_src * ref->item_size,
               dst_kind, src_kind, dst_dim + 1, src_dim + 1,
               1, stat, src_type);
          dst_index[dst_dim]
          += GFC_DIMENSION_STRIDE (dst->dim[dst_dim]);
          array_offset_src += ref->u.a.dim[src_dim].s.stride;
        }
      return;
    case CAF_ARR_REF_SINGLE:
      array_offset_src = ref->u.a.dim[src_dim].s.start;
      get_for_ref (ref, i, dst_index, single_token, dst, NULL, ds,
               sr + array_offset_src * ref->item_size,
               dst_kind, src_kind, dst_dim, src_dim + 1, 1,
               stat, src_type);
      return;
    /* The OPEN_* are mapped to a RANGE and therefore cannot occur.  */
    case CAF_ARR_REF_OPEN_END:
    case CAF_ARR_REF_OPEN_START:
    default:
      caf_runtime_error (unreachable);
    }
      return;
    default:
      caf_runtime_error (unreachable);
    }
}


void
_gfortran_caf_get_by_ref (caf_token_t token,
              int image_index __attribute__ ((unused)),
              gfc_descriptor_t *dst, caf_reference_t *refs,
              int dst_kind, int src_kind,
              bool may_require_tmp __attribute__ ((unused)),
              bool dst_reallocatable, int *stat,
              int src_type)
{
  const char vecrefunknownkind[] = "libcaf_single::caf_get_by_ref(): "
                   "unknown kind in vector-ref.\n";
  const char unknownreftype[] = "libcaf_single::caf_get_by_ref(): "
                "unknown reference type.\n";
  const char unknownarrreftype[] = "libcaf_single::caf_get_by_ref(): "
                   "unknown array reference type.\n";
  const char rankoutofrange[] = "libcaf_single::caf_get_by_ref(): "
                "rank out of range.\n";
  const char extentoutofrange[] = "libcaf_single::caf_get_by_ref(): "
                  "extent out of range.\n";
  const char cannotallocdst[] = "libcaf_single::caf_get_by_ref(): "
                "cannot allocate memory.\n";
  const char nonallocextentmismatch[] = "libcaf_single::caf_get_by_ref(): "
      "extent of non-allocatable arrays mismatch (%lu != %lu).\n";
  const char doublearrayref[] = "libcaf_single::caf_get_by_ref(): "
      "two or more array part references are not supported.\n";
  size_t size, i;
  size_t dst_index[GFC_MAX_DIMENSIONS];
  int dst_rank = GFC_DESCRIPTOR_RANK (dst);
  int dst_cur_dim = 0;
  size_t src_size = 0;
  caf_single_token_t single_token = TOKEN (token);
  void *memptr = single_token->memptr;
  gfc_descriptor_t *src = single_token->desc;
  caf_reference_t *riter = refs;
  long delta;
  /* Reallocation of dst.data is needed (e.g., array to small).  */
  bool realloc_needed;
  /* Reallocation of dst.data is required, because data is not alloced at
     all.  */
  bool realloc_required;
  bool extent_mismatch = false;
  /* Set when the first non-scalar array reference is encountered.  */
  bool in_array_ref = false;
  bool array_extent_fixed = false;
  realloc_needed = realloc_required = GFC_DESCRIPTOR_DATA (dst) == NULL;

  assert (!realloc_needed || dst_reallocatable);

  if (stat)
    *stat = 0;

  /* Compute the size of the result.  In the beginning size just counts the
     number of elements.  */
  size = 1;
  while (riter)
    {
      switch (riter->type)
    {
    case CAF_REF_COMPONENT:
      if (riter->u.c.caf_token_offset)
        {
          single_token = *(caf_single_token_t*)
                     (memptr + riter->u.c.caf_token_offset);
          memptr = single_token->memptr;
          src = single_token->desc;
        }
      else
        {
          memptr += riter->u.c.offset;
          /* When the next ref is an array ref, assume there is an
         array descriptor at memptr.  Note, static arrays do not have
         a descriptor.  */
          if (riter->next && riter->next->type == CAF_REF_ARRAY)
        src = (gfc_descriptor_t *)memptr;
          else
        src = NULL;
        }
      break;
    case CAF_REF_ARRAY:
      for (i = 0; riter->u.a.mode[i] != CAF_ARR_REF_NONE; ++i)
        {
          switch (riter->u.a.mode[i])
        {
        case CAF_ARR_REF_VECTOR:
          delta = riter->u.a.dim[i].v.nvec;
#define KINDCASE(kind, type) case kind: \
            memptr += (((index_type) \
            ((type *)riter->u.a.dim[i].v.vector)[0]) \
            - GFC_DIMENSION_LBOUND (src->dim[i])) \
            * GFC_DIMENSION_STRIDE (src->dim[i]) \
            * riter->item_size; \
            break

          switch (riter->u.a.dim[i].v.kind)
            {
            KINDCASE (1, GFC_INTEGER_1);
            KINDCASE (2, GFC_INTEGER_2);
            KINDCASE (4, GFC_INTEGER_4);
#ifdef HAVE_GFC_INTEGER_8
            KINDCASE (8, GFC_INTEGER_8);
#endif
#ifdef HAVE_GFC_INTEGER_16
            KINDCASE (16, GFC_INTEGER_16);
#endif
            default:
              caf_internal_error (vecrefunknownkind, stat, NULL, 0);
              return;
            }
#undef KINDCASE
          break;
        case CAF_ARR_REF_FULL:
          COMPUTE_NUM_ITEMS (delta,
                     riter->u.a.dim[i].s.stride,
                     GFC_DIMENSION_LBOUND (src->dim[i]),
                     GFC_DIMENSION_UBOUND (src->dim[i]));
          /* The memptr stays unchanged when ref'ing the first element
             in a dimension.  */
          break;
        case CAF_ARR_REF_RANGE:
          COMPUTE_NUM_ITEMS (delta,
                     riter->u.a.dim[i].s.stride,
                     riter->u.a.dim[i].s.start,
                     riter->u.a.dim[i].s.end);
          memptr += (riter->u.a.dim[i].s.start
                 - GFC_DIMENSION_LBOUND (src->dim[i]))
              * GFC_DIMENSION_STRIDE (src->dim[i])
              * riter->item_size;
          break;
        case CAF_ARR_REF_SINGLE:
          delta = 1;
          memptr += (riter->u.a.dim[i].s.start
                 - GFC_DIMENSION_LBOUND (src->dim[i]))
              * GFC_DIMENSION_STRIDE (src->dim[i])
              * riter->item_size;
          break;
        case CAF_ARR_REF_OPEN_END:
          COMPUTE_NUM_ITEMS (delta,
                     riter->u.a.dim[i].s.stride,
                     riter->u.a.dim[i].s.start,
                     GFC_DIMENSION_UBOUND (src->dim[i]));
          memptr += (riter->u.a.dim[i].s.start
                 - GFC_DIMENSION_LBOUND (src->dim[i]))
              * GFC_DIMENSION_STRIDE (src->dim[i])
              * riter->item_size;
          break;
        case CAF_ARR_REF_OPEN_START:
          COMPUTE_NUM_ITEMS (delta,
                     riter->u.a.dim[i].s.stride,
                     GFC_DIMENSION_LBOUND (src->dim[i]),
                     riter->u.a.dim[i].s.end);
          /* The memptr stays unchanged when ref'ing the first element
             in a dimension.  */
          break;
        default:
          caf_internal_error (unknownarrreftype, stat, NULL, 0);
          return;
        }
          if (delta <= 0)
        return;
          /* Check the various properties of the destination array.
         Is an array expected and present?  */
          if (delta > 1 && dst_rank == 0)
        {
          /* No, an array is required, but not provided.  */
          caf_internal_error (extentoutofrange, stat, NULL, 0);
          return;
        }
          /* Special mode when called by __caf_sendget_by_ref ().  */
          if (dst_rank == -1 && GFC_DESCRIPTOR_DATA (dst) == NULL)
        {
          dst_rank = dst_cur_dim + 1;
          GFC_DESCRIPTOR_RANK (dst) = dst_rank;
          GFC_DESCRIPTOR_SIZE (dst) = dst_kind;
        }
          /* When dst is an array.  */
          if (dst_rank > 0)
        {
          /* Check that dst_cur_dim is valid for dst.  Can be
             superceeded only by scalar data.  */
          if (dst_cur_dim >= dst_rank && delta != 1)
            {
              caf_internal_error (rankoutofrange, stat, NULL, 0);
              return;
            }
          /* Do further checks, when the source is not scalar.  */
          else if (delta != 1)
            {
              /* Check that the extent is not scalar and we are not in
             an array ref for the dst side.  */
              if (!in_array_ref)
            {
              /* Check that this is the non-scalar extent.  */
              if (!array_extent_fixed)
                {
                  /* In an array extent now.  */
                  in_array_ref = true;
                  /* Check that we haven't skipped any scalar
                 dimensions yet and that the dst is
                 compatible.  */
                  if (i > 0
                  && dst_rank == GFC_DESCRIPTOR_RANK (src))
                {
                  if (dst_reallocatable)
                    {
                      /* Dst is reallocatable, which means that
                     the bounds are not set.  Set them.  */
                      for (dst_cur_dim= 0; dst_cur_dim < (int)i;
                       ++dst_cur_dim)
                       GFC_DIMENSION_SET (dst->dim[dst_cur_dim],
                              1, 1, 1);
                    }
                  else
                    dst_cur_dim = i;
                }
                  /* Else press thumbs, that there are enough
                 dimensional refs to come.  Checked below.  */
                }
              else
                {
                  caf_internal_error (doublearrayref, stat, NULL,
                          0);
                  return;
                }
            }
              /* When the realloc is required, then no extent may have
             been set.  */
              extent_mismatch = realloc_required
              || GFC_DESCRIPTOR_EXTENT (dst, dst_cur_dim) != delta;
              /* When it already known, that a realloc is needed or
             the extent does not match the needed one.  */
              if (realloc_required || realloc_needed
              || extent_mismatch)
            {
              /* Check whether dst is reallocatable.  */
              if (unlikely (!dst_reallocatable))
                {
                  caf_internal_error (nonallocextentmismatch, stat,
                          NULL, 0, delta,
                          GFC_DESCRIPTOR_EXTENT (dst,
                                  dst_cur_dim));
                  return;
                }
              /* Only report an error, when the extent needs to be
                 modified, which is not allowed.  */
              else if (!dst_reallocatable && extent_mismatch)
                {
                  caf_internal_error (extentoutofrange, stat, NULL,
                          0);
                  return;
                }
              realloc_needed = true;
            }
              /* Only change the extent when it does not match.  This is
             to prevent resetting given array bounds.  */
              if (extent_mismatch)
            GFC_DIMENSION_SET (dst->dim[dst_cur_dim], 1, delta,
                       size);
            }

          /* Only increase the dim counter, when in an array ref.  */
          if (in_array_ref && dst_cur_dim < dst_rank)
            ++dst_cur_dim;
        }
          size *= (index_type)delta;
        }
      if (in_array_ref)
        {
          array_extent_fixed = true;
          in_array_ref = false;
          /* Check, if we got less dimensional refs than the rank of dst
         expects.  */
          assert (dst_cur_dim == GFC_DESCRIPTOR_RANK (dst));
        }
      break;
    case CAF_REF_STATIC_ARRAY:
      for (i = 0; riter->u.a.mode[i] != CAF_ARR_REF_NONE; ++i)
        {
          switch (riter->u.a.mode[i])
        {
        case CAF_ARR_REF_VECTOR:
          delta = riter->u.a.dim[i].v.nvec;
#define KINDCASE(kind, type) case kind: \
            memptr += ((type *)riter->u.a.dim[i].v.vector)[0] \
            * riter->item_size; \
            break

          switch (riter->u.a.dim[i].v.kind)
            {
            KINDCASE (1, GFC_INTEGER_1);
            KINDCASE (2, GFC_INTEGER_2);
            KINDCASE (4, GFC_INTEGER_4);
#ifdef HAVE_GFC_INTEGER_8
            KINDCASE (8, GFC_INTEGER_8);
#endif
#ifdef HAVE_GFC_INTEGER_16
            KINDCASE (16, GFC_INTEGER_16);
#endif
            default:
              caf_internal_error (vecrefunknownkind, stat, NULL, 0);
              return;
            }
#undef KINDCASE
          break;
        case CAF_ARR_REF_FULL:
          delta = riter->u.a.dim[i].s.end / riter->u.a.dim[i].s.stride
              + 1;
          /* The memptr stays unchanged when ref'ing the first element
             in a dimension.  */
          break;
        case CAF_ARR_REF_RANGE:
          COMPUTE_NUM_ITEMS (delta,
                     riter->u.a.dim[i].s.stride,
                     riter->u.a.dim[i].s.start,
                     riter->u.a.dim[i].s.end);
          memptr += riter->u.a.dim[i].s.start
              * riter->u.a.dim[i].s.stride
              * riter->item_size;
          break;
        case CAF_ARR_REF_SINGLE:
          delta = 1;
          memptr += riter->u.a.dim[i].s.start
              * riter->u.a.dim[i].s.stride
              * riter->item_size;
          break;
        case CAF_ARR_REF_OPEN_END:
          /* This and OPEN_START are mapped to a RANGE and therefore
             cannot occur here.  */
        case CAF_ARR_REF_OPEN_START:
        default:
          caf_internal_error (unknownarrreftype, stat, NULL, 0);
          return;
        }
          if (delta <= 0)
        return;
          /* Check the various properties of the destination array.
         Is an array expected and present?  */
          if (delta > 1 && dst_rank == 0)
        {
          /* No, an array is required, but not provided.  */
          caf_internal_error (extentoutofrange, stat, NULL, 0);
          return;
        }
          /* Special mode when called by __caf_sendget_by_ref ().  */
          if (dst_rank == -1 && GFC_DESCRIPTOR_DATA (dst) == NULL)
        {
          dst_rank = dst_cur_dim + 1;
          GFC_DESCRIPTOR_RANK (dst) = dst_rank;
          GFC_DESCRIPTOR_SIZE (dst) = dst_kind;
        }
          /* When dst is an array.  */
          if (dst_rank > 0)
        {
          /* Check that dst_cur_dim is valid for dst.  Can be
             superceeded only by scalar data.  */
          if (dst_cur_dim >= dst_rank && delta != 1)
            {
              caf_internal_error (rankoutofrange, stat, NULL, 0);
              return;
            }
          /* Do further checks, when the source is not scalar.  */
          else if (delta != 1)
            {
              /* Check that the extent is not scalar and we are not in
             an array ref for the dst side.  */
              if (!in_array_ref)
            {
              /* Check that this is the non-scalar extent.  */
              if (!array_extent_fixed)
                {
                  /* In an array extent now.  */
                  in_array_ref = true;
                  /* The dst is not reallocatable, so nothing more
                 to do, then correct the dim counter.  */
                  dst_cur_dim = i;
                }
              else
                {
                  caf_internal_error (doublearrayref, stat, NULL,
                          0);
                  return;
                }
            }
              /* When the realloc is required, then no extent may have
             been set.  */
              extent_mismatch = realloc_required
              || GFC_DESCRIPTOR_EXTENT (dst, dst_cur_dim) != delta;
              /* When it is already known, that a realloc is needed or
             the extent does not match the needed one.  */
              if (realloc_required || realloc_needed
              || extent_mismatch)
            {
              /* Check whether dst is reallocatable.  */
              if (unlikely (!dst_reallocatable))
                {
                  caf_internal_error (nonallocextentmismatch, stat,
                          NULL, 0, delta,
                          GFC_DESCRIPTOR_EXTENT (dst,
                                  dst_cur_dim));
                  return;
                }
              /* Only report an error, when the extent needs to be
                 modified, which is not allowed.  */
              else if (!dst_reallocatable && extent_mismatch)
                {
                  caf_internal_error (extentoutofrange, stat, NULL,
                          0);
                  return;
                }
              realloc_needed = true;
            }
              /* Only change the extent when it does not match.  This is
             to prevent resetting given array bounds.  */
              if (extent_mismatch)
            GFC_DIMENSION_SET (dst->dim[dst_cur_dim], 1, delta,
                       size);
            }
          /* Only increase the dim counter, when in an array ref.  */
          if (in_array_ref && dst_cur_dim < dst_rank)
            ++dst_cur_dim;
        }
          size *= (index_type)delta;
        }
      if (in_array_ref)
        {
          array_extent_fixed = true;
          in_array_ref = false;
          /* Check, if we got less dimensional refs than the rank of dst
         expects.  */
          assert (dst_cur_dim == GFC_DESCRIPTOR_RANK (dst));
        }
      break;
    default:
      caf_internal_error (unknownreftype, stat, NULL, 0);
      return;
    }
      src_size = riter->item_size;
      riter = riter->next;
    }
  if (size == 0 || src_size == 0)
    return;
  /* Postcondition:
     - size contains the number of elements to store in the destination array,
     - src_size gives the size in bytes of each item in the destination array.
  */

  if (realloc_needed)
    {
      if (!array_extent_fixed)
    {
      assert (size == 1);
      /* Special mode when called by __caf_sendget_by_ref ().  */
      if (dst_rank == -1 && GFC_DESCRIPTOR_DATA (dst) == NULL)
        {
          dst_rank = dst_cur_dim + 1;
          GFC_DESCRIPTOR_RANK (dst) = dst_rank;
          GFC_DESCRIPTOR_SIZE (dst) = dst_kind;
        }
      /* This can happen only, when the result is scalar.  */
      for (dst_cur_dim = 0; dst_cur_dim < dst_rank; ++dst_cur_dim)
        GFC_DIMENSION_SET (dst->dim[dst_cur_dim], 1, 1, 1);
    }

      GFC_DESCRIPTOR_DATA (dst) = malloc (size * GFC_DESCRIPTOR_SIZE (dst));
      if (unlikely (GFC_DESCRIPTOR_DATA (dst) == NULL))
    {
      caf_internal_error (cannotallocdst, stat, NULL, 0);
      return;
    }
    }

  /* Reset the token.  */
  single_token = TOKEN (token);
  memptr = single_token->memptr;
  src = single_token->desc;
  memset(dst_index, 0, sizeof (dst_index));
  i = 0;
  get_for_ref (refs, &i, dst_index, single_token, dst, src,
           GFC_DESCRIPTOR_DATA (dst), memptr, dst_kind, src_kind, 0, 0,
           1, stat, src_type);
}


static void
send_by_ref (caf_reference_t *ref, size_t *i, size_t *src_index,
         caf_single_token_t single_token, gfc_descriptor_t *dst,
         gfc_descriptor_t *src, void *ds, void *sr,
         int dst_kind, int src_kind, size_t dst_dim, size_t src_dim,
         size_t num, size_t size, int *stat, int dst_type)
{
  const char vecrefunknownkind[] = "libcaf_single::caf_send_by_ref(): "
      "unknown kind in vector-ref.\n";
  ptrdiff_t extent_dst = 1, array_offset_dst = 0, stride_dst;
  const size_t src_rank = GFC_DESCRIPTOR_RANK (src);

  if (unlikely (ref == NULL))
    /* May be we should issue an error here, because this case should not
       occur.  */
    return;

  if (ref->next == NULL)
    {
      size_t src_size = GFC_DESCRIPTOR_SIZE (src);
      ptrdiff_t array_offset_src = 0;;

      switch (ref->type)
    {
    case CAF_REF_COMPONENT:
      if (ref->u.c.caf_token_offset > 0)
        {
          if (*(void**)(ds + ref->u.c.offset) == NULL)
        {
          /* Create a scalar temporary array descriptor.  */
          gfc_descriptor_t static_dst;
          GFC_DESCRIPTOR_DATA (&static_dst) = NULL;
          GFC_DESCRIPTOR_DTYPE (&static_dst)
              = GFC_DESCRIPTOR_DTYPE (src);
          /* The component can be allocated now, because it is a
             scalar.  */
          _gfortran_caf_register (ref->item_size,
                      CAF_REGTYPE_COARRAY_ALLOC,
                      ds + ref->u.c.caf_token_offset,
                      &static_dst, stat, NULL, 0);
          single_token = *(caf_single_token_t *)
                           (ds + ref->u.c.caf_token_offset);
          /* In case of an error in allocation return.  When stat is
             NULL, then register_component() terminates on error.  */
          if (stat != NULL && *stat)
            return;
          /* Publish the allocated memory.  */
          *((void **)(ds + ref->u.c.offset))
              = GFC_DESCRIPTOR_DATA (&static_dst);
          ds = GFC_DESCRIPTOR_DATA (&static_dst);
          /* Set the type from the src.  */
          dst_type = GFC_DESCRIPTOR_TYPE (src);
        }
          else
        {
          single_token = *(caf_single_token_t *)
                           (ds + ref->u.c.caf_token_offset);
          dst = single_token->desc;
          if (dst)
            {
              ds = GFC_DESCRIPTOR_DATA (dst);
              dst_type = GFC_DESCRIPTOR_TYPE (dst);
            }
          else
            ds = *(void **)(ds + ref->u.c.offset);
        }
          copy_data (ds, sr, dst_type, GFC_DESCRIPTOR_TYPE (src),
             dst_kind, src_kind, ref->item_size, src_size, 1, stat);
        }
      else
        copy_data (ds + ref->u.c.offset, sr, dst_type,
               GFC_DESCRIPTOR_TYPE (src),
               dst_kind, src_kind, ref->item_size, src_size, 1, stat);
      ++(*i);
      return;
    case CAF_REF_STATIC_ARRAY:
      /* Intentionally fall through.  */
    case CAF_REF_ARRAY:
      if (ref->u.a.mode[dst_dim] == CAF_ARR_REF_NONE)
        {
          if (src_rank > 0)
        {
          for (size_t d = 0; d < src_rank; ++d)
            array_offset_src += src_index[d];
          copy_data (ds, sr + array_offset_src * src_size,
                 dst_type, GFC_DESCRIPTOR_TYPE (src), dst_kind,
                 src_kind, ref->item_size, src_size, num, stat);
        }
          else
        copy_data (ds, sr, dst_type, GFC_DESCRIPTOR_TYPE (src),
               dst_kind, src_kind, ref->item_size, src_size, num,
               stat);
          *i += num;
          return;
        }
      break;
    default:
      caf_runtime_error (unreachable);
    }
    }

  switch (ref->type)
    {
    case CAF_REF_COMPONENT:
      if (ref->u.c.caf_token_offset > 0)
    {
      if (*(void**)(ds + ref->u.c.offset) == NULL)
        {
          /* This component refs an unallocated array.  Non-arrays are
         caught in the if (!ref->next) above.  */
          dst = (gfc_descriptor_t *)(ds + ref->u.c.offset);
          /* Assume that the rank and the dimensions fit for copying src
         to dst.  */
          GFC_DESCRIPTOR_DTYPE (dst) = GFC_DESCRIPTOR_DTYPE (src);
          dst->offset = 0;
          stride_dst = 1;
          for (size_t d = 0; d < src_rank; ++d)
        {
          extent_dst = GFC_DIMENSION_EXTENT (src->dim[d]);
          GFC_DIMENSION_LBOUND (dst->dim[d]) = 0;
          GFC_DIMENSION_UBOUND (dst->dim[d]) = extent_dst - 1;
          GFC_DIMENSION_STRIDE (dst->dim[d]) = stride_dst;
          stride_dst *= extent_dst;
        }
          /* Null the data-pointer to make register_component allocate
         its own memory.  */
          GFC_DESCRIPTOR_DATA (dst) = NULL;

          /* The size of the array is given by size.  */
          _gfortran_caf_register (size * ref->item_size,
                      CAF_REGTYPE_COARRAY_ALLOC,
                      ds + ref->u.c.caf_token_offset,
                      dst, stat, NULL, 0);
          /* In case of an error in allocation return.  When stat is
         NULL, then register_component() terminates on error.  */
          if (stat != NULL && *stat)
        return;
        }
      single_token = *(caf_single_token_t*)(ds + ref->u.c.caf_token_offset);
      /* When a component is allocatable (caf_token_offset != 0) and not an
         array (ref->next->type == CAF_REF_COMPONENT), then ds has to be
         dereffed.  */
      if (ref->next && ref->next->type == CAF_REF_COMPONENT)
        ds = *(void **)(ds + ref->u.c.offset);
      else
        ds += ref->u.c.offset;

      send_by_ref (ref->next, i, src_index, single_token,
               single_token->desc, src, ds, sr,
               dst_kind, src_kind, 0, src_dim, 1, size, stat, dst_type);
    }
      else
    send_by_ref (ref->next, i, src_index, single_token,
             (gfc_descriptor_t *)(ds + ref->u.c.offset), src,
             ds + ref->u.c.offset, sr, dst_kind, src_kind, 0, src_dim,
             1, size, stat, dst_type);
      return;
    case CAF_REF_ARRAY:
      if (ref->u.a.mode[dst_dim] == CAF_ARR_REF_NONE)
    {
      send_by_ref (ref->next, i, src_index, single_token,
               (gfc_descriptor_t *)ds, src, ds, sr, dst_kind, src_kind,
               0, src_dim, 1, size, stat, dst_type);
      return;
    }
      /* Only when on the left most index switch the data pointer to
     the array's data pointer.  And only for non-static arrays.  */
      if (dst_dim == 0 && ref->type != CAF_REF_STATIC_ARRAY)
    ds = GFC_DESCRIPTOR_DATA (dst);
      switch (ref->u.a.mode[dst_dim])
    {
    case CAF_ARR_REF_VECTOR:
      array_offset_dst = 0;
      src_index[src_dim] = 0;
      for (size_t idx = 0; idx < ref->u.a.dim[dst_dim].v.nvec;
           ++idx)
        {
#define KINDCASE(kind, type) case kind: \
          array_offset_dst = (((index_type) \
          ((type *)ref->u.a.dim[dst_dim].v.vector)[idx]) \
          - GFC_DIMENSION_LBOUND (dst->dim[dst_dim])) \
          * GFC_DIMENSION_STRIDE (dst->dim[dst_dim]); \
          break

          switch (ref->u.a.dim[dst_dim].v.kind)
        {
        KINDCASE (1, GFC_INTEGER_1);
        KINDCASE (2, GFC_INTEGER_2);
        KINDCASE (4, GFC_INTEGER_4);
#ifdef HAVE_GFC_INTEGER_8
        KINDCASE (8, GFC_INTEGER_8);
#endif
#ifdef HAVE_GFC_INTEGER_16
        KINDCASE (16, GFC_INTEGER_16);
#endif
        default:
          caf_internal_error (vecrefunknownkind, stat, NULL, 0);
          return;
        }
#undef KINDCASE

          send_by_ref (ref, i, src_index, single_token, dst, src,
               ds + array_offset_dst * ref->item_size, sr,
               dst_kind, src_kind, dst_dim + 1, src_dim + 1,
               1, size, stat, dst_type);
          if (src_rank > 0)
        src_index[src_dim]
            += GFC_DIMENSION_STRIDE (src->dim[src_dim]);
        }
      return;
    case CAF_ARR_REF_FULL:
      COMPUTE_NUM_ITEMS (extent_dst,
                 ref->u.a.dim[dst_dim].s.stride,
                 GFC_DIMENSION_LBOUND (dst->dim[dst_dim]),
                 GFC_DIMENSION_UBOUND (dst->dim[dst_dim]));
      array_offset_dst = 0;
      stride_dst = GFC_DIMENSION_STRIDE (dst->dim[dst_dim])
          * ref->u.a.dim[dst_dim].s.stride;
      src_index[src_dim] = 0;
      for (index_type idx = 0; idx < extent_dst;
           ++idx, array_offset_dst += stride_dst)
        {
          send_by_ref (ref, i, src_index, single_token, dst, src,
               ds + array_offset_dst * ref->item_size, sr,
               dst_kind, src_kind, dst_dim + 1, src_dim + 1,
               1, size, stat, dst_type);
          if (src_rank > 0)
        src_index[src_dim]
            += GFC_DIMENSION_STRIDE (src->dim[src_dim]);
        }
      return;
    case CAF_ARR_REF_RANGE:
      COMPUTE_NUM_ITEMS (extent_dst,
                 ref->u.a.dim[dst_dim].s.stride,
                 ref->u.a.dim[dst_dim].s.start,
                 ref->u.a.dim[dst_dim].s.end);
      array_offset_dst = ref->u.a.dim[dst_dim].s.start
          - GFC_DIMENSION_LBOUND (dst->dim[dst_dim]);
      stride_dst = GFC_DIMENSION_STRIDE (dst->dim[dst_dim])
          * ref->u.a.dim[dst_dim].s.stride;
      src_index[src_dim] = 0;
      for (index_type idx = 0; idx < extent_dst; ++idx)
        {
          send_by_ref (ref, i, src_index, single_token, dst, src,
               ds + array_offset_dst * ref->item_size, sr,
               dst_kind, src_kind, dst_dim + 1, src_dim + 1,
               1, size, stat, dst_type);
          if (src_rank > 0)
        src_index[src_dim]
            += GFC_DIMENSION_STRIDE (src->dim[src_dim]);
          array_offset_dst += stride_dst;
        }
      return;
    case CAF_ARR_REF_SINGLE:
      array_offset_dst = (ref->u.a.dim[dst_dim].s.start
                   - GFC_DIMENSION_LBOUND (dst->dim[dst_dim]))
                 * GFC_DIMENSION_STRIDE (dst->dim[dst_dim]);
      send_by_ref (ref, i, src_index, single_token, dst, src, ds
               + array_offset_dst * ref->item_size, sr,
               dst_kind, src_kind, dst_dim + 1, src_dim, 1,
               size, stat, dst_type);
      return;
    case CAF_ARR_REF_OPEN_END:
      COMPUTE_NUM_ITEMS (extent_dst,
                 ref->u.a.dim[dst_dim].s.stride,
                 ref->u.a.dim[dst_dim].s.start,
                 GFC_DIMENSION_UBOUND (dst->dim[dst_dim]));
      array_offset_dst = ref->u.a.dim[dst_dim].s.start
          - GFC_DIMENSION_LBOUND (dst->dim[dst_dim]);
      stride_dst = GFC_DIMENSION_STRIDE (dst->dim[dst_dim])
          * ref->u.a.dim[dst_dim].s.stride;
      src_index[src_dim] = 0;
      for (index_type idx = 0; idx < extent_dst; ++idx)
        {
          send_by_ref (ref, i, src_index, single_token, dst, src,
               ds + array_offset_dst * ref->item_size, sr,
               dst_kind, src_kind, dst_dim + 1, src_dim + 1,
               1, size, stat, dst_type);
          if (src_rank > 0)
        src_index[src_dim]
            += GFC_DIMENSION_STRIDE (src->dim[src_dim]);
          array_offset_dst += stride_dst;
        }
      return;
    case CAF_ARR_REF_OPEN_START:
      COMPUTE_NUM_ITEMS (extent_dst,
                 ref->u.a.dim[dst_dim].s.stride,
                 GFC_DIMENSION_LBOUND (dst->dim[dst_dim]),
                 ref->u.a.dim[dst_dim].s.end);
      array_offset_dst = 0;
      stride_dst = GFC_DIMENSION_STRIDE (dst->dim[dst_dim])
          * ref->u.a.dim[dst_dim].s.stride;
      src_index[src_dim] = 0;
      for (index_type idx = 0; idx < extent_dst; ++idx)
        {
          send_by_ref (ref, i, src_index, single_token, dst, src,
               ds + array_offset_dst * ref->item_size, sr,
               dst_kind, src_kind, dst_dim + 1, src_dim + 1,
               1, size, stat, dst_type);
          if (src_rank > 0)
        src_index[src_dim]
            += GFC_DIMENSION_STRIDE (src->dim[src_dim]);
          array_offset_dst += stride_dst;
        }
      return;
    default:
      caf_runtime_error (unreachable);
    }
      return;
    case CAF_REF_STATIC_ARRAY:
      if (ref->u.a.mode[dst_dim] == CAF_ARR_REF_NONE)
    {
      send_by_ref (ref->next, i, src_index, single_token, NULL,
               src, ds, sr, dst_kind, src_kind,
               0, src_dim, 1, size, stat, dst_type);
      return;
    }
      switch (ref->u.a.mode[dst_dim])
    {
    case CAF_ARR_REF_VECTOR:
      array_offset_dst = 0;
      src_index[src_dim] = 0;
      for (size_t idx = 0; idx < ref->u.a.dim[dst_dim].v.nvec;
           ++idx)
        {
#define KINDCASE(kind, type) case kind: \
         array_offset_dst = ((type *)ref->u.a.dim[dst_dim].v.vector)[idx]; \
          break

          switch (ref->u.a.dim[dst_dim].v.kind)
        {
        KINDCASE (1, GFC_INTEGER_1);
        KINDCASE (2, GFC_INTEGER_2);
        KINDCASE (4, GFC_INTEGER_4);
#ifdef HAVE_GFC_INTEGER_8
        KINDCASE (8, GFC_INTEGER_8);
#endif
#ifdef HAVE_GFC_INTEGER_16
        KINDCASE (16, GFC_INTEGER_16);
#endif
        default:
          caf_runtime_error (unreachable);
          return;
        }
#undef KINDCASE

          send_by_ref (ref, i, src_index, single_token, NULL, src,
               ds + array_offset_dst * ref->item_size, sr,
               dst_kind, src_kind, dst_dim + 1, src_dim + 1,
               1, size, stat, dst_type);
          src_index[src_dim]
          += GFC_DIMENSION_STRIDE (src->dim[src_dim]);
        }
      return;
    case CAF_ARR_REF_FULL:
      src_index[src_dim] = 0;
      for (array_offset_dst = 0 ;
           array_offset_dst <= ref->u.a.dim[dst_dim].s.end;
           array_offset_dst += ref->u.a.dim[dst_dim].s.stride)
        {
          send_by_ref (ref, i, src_index, single_token, NULL, src,
               ds + array_offset_dst * ref->item_size, sr,
               dst_kind, src_kind, dst_dim + 1, src_dim + 1,
               1, size, stat, dst_type);
          if (src_rank > 0)
        src_index[src_dim]
            += GFC_DIMENSION_STRIDE (src->dim[src_dim]);
        }
      return;
    case CAF_ARR_REF_RANGE:
      COMPUTE_NUM_ITEMS (extent_dst,
                 ref->u.a.dim[dst_dim].s.stride,
                 ref->u.a.dim[dst_dim].s.start,
                 ref->u.a.dim[dst_dim].s.end);
      array_offset_dst = ref->u.a.dim[dst_dim].s.start;
      src_index[src_dim] = 0;
      for (index_type idx = 0; idx < extent_dst; ++idx)
        {
          send_by_ref (ref, i, src_index, single_token, NULL, src,
               ds + array_offset_dst * ref->item_size, sr,
               dst_kind, src_kind, dst_dim + 1, src_dim + 1,
               1, size, stat, dst_type);
          if (src_rank > 0)
        src_index[src_dim]
            += GFC_DIMENSION_STRIDE (src->dim[src_dim]);
          array_offset_dst += ref->u.a.dim[dst_dim].s.stride;
        }
      return;
    case CAF_ARR_REF_SINGLE:
      array_offset_dst = ref->u.a.dim[dst_dim].s.start;
      send_by_ref (ref, i, src_index, single_token, NULL, src,
               ds + array_offset_dst * ref->item_size, sr,
               dst_kind, src_kind, dst_dim + 1, src_dim, 1,
               size, stat, dst_type);
      return;
    /* The OPEN_* are mapped to a RANGE and therefore cannot occur.  */
    case CAF_ARR_REF_OPEN_END:
    case CAF_ARR_REF_OPEN_START:
    default:
      caf_runtime_error (unreachable);
    }
      return;
    default:
      caf_runtime_error (unreachable);
    }
}


void
_gfortran_caf_send_by_ref (caf_token_t token,
               int image_index __attribute__ ((unused)),
               gfc_descriptor_t *src, caf_reference_t *refs,
               int dst_kind, int src_kind,
               bool may_require_tmp __attribute__ ((unused)),
               bool dst_reallocatable, int *stat, int dst_type)
{
  const char vecrefunknownkind[] = "libcaf_single::caf_get_by_ref(): "
                   "unknown kind in vector-ref.\n";
  const char unknownreftype[] = "libcaf_single::caf_send_by_ref(): "
                "unknown reference type.\n";
  const char unknownarrreftype[] = "libcaf_single::caf_send_by_ref(): "
                   "unknown array reference type.\n";
  const char rankoutofrange[] = "libcaf_single::caf_send_by_ref(): "
                "rank out of range.\n";
  const char realloconinnerref[] = "libcaf_single::caf_send_by_ref(): "
      "reallocation of array followed by component ref not allowed.\n";
  const char cannotallocdst[] = "libcaf_single::caf_send_by_ref(): "
                "cannot allocate memory.\n";
  const char nonallocextentmismatch[] = "libcaf_single::caf_send_by_ref(): "
      "extent of non-allocatable array mismatch.\n";
  const char innercompref[] = "libcaf_single::caf_send_by_ref(): "
      "inner unallocated component detected.\n";
  size_t size, i;
  size_t dst_index[GFC_MAX_DIMENSIONS];
  int src_rank = GFC_DESCRIPTOR_RANK (src);
  int src_cur_dim = 0;
  size_t src_size = 0;
  caf_single_token_t single_token = TOKEN (token);
  void *memptr = single_token->memptr;
  gfc_descriptor_t *dst = single_token->desc;
  caf_reference_t *riter = refs;
  long delta;
  bool extent_mismatch;
  /* Note that the component is not allocated yet.  */
  index_type new_component_idx = -1;

  if (stat)
    *stat = 0;

  /* Compute the size of the result.  In the beginning size just counts the
     number of elements.  */
  size = 1;
  while (riter)
    {
      switch (riter->type)
    {
    case CAF_REF_COMPONENT:
      if (unlikely (new_component_idx != -1))
        {
          /* Allocating a component in the middle of a component ref is not
         support.  We don't know the type to allocate.  */
          caf_internal_error (innercompref, stat, NULL, 0);
          return;
        }
      if (riter->u.c.caf_token_offset > 0)
        {
          /* Check whether the allocatable component is zero, then no
         token is present, too.  The token's pointer is not cleared
         when the structure is initialized.  */
          if (*(void**)(memptr + riter->u.c.offset) == NULL)
        {
          /* This component is not yet allocated.  Check that it is
             allocatable here.  */
          if (!dst_reallocatable)
            {
              caf_internal_error (cannotallocdst, stat, NULL, 0);
              return;
            }
          single_token = NULL;
          memptr = NULL;
          dst = NULL;
          break;
        }
          single_token = *(caf_single_token_t*)
                     (memptr + riter->u.c.caf_token_offset);
          memptr += riter->u.c.offset;
          dst = single_token->desc;
        }
      else
        {
          /* Regular component.  */
          memptr += riter->u.c.offset;
          dst = (gfc_descriptor_t *)memptr;
        }
      break;
    case CAF_REF_ARRAY:
      if (dst != NULL)
        memptr = GFC_DESCRIPTOR_DATA (dst);
      else
        dst = src;
      /* When the dst array needs to be allocated, then look at the
         extent of the source array in the dimension dst_cur_dim.  */
      for (i = 0; riter->u.a.mode[i] != CAF_ARR_REF_NONE; ++i)
        {
          switch (riter->u.a.mode[i])
        {
        case CAF_ARR_REF_VECTOR:
          delta = riter->u.a.dim[i].v.nvec;
#define KINDCASE(kind, type) case kind: \
            memptr += (((index_type) \
            ((type *)riter->u.a.dim[i].v.vector)[0]) \
            - GFC_DIMENSION_LBOUND (dst->dim[i])) \
            * GFC_DIMENSION_STRIDE (dst->dim[i]) \
            * riter->item_size; \
            break

          switch (riter->u.a.dim[i].v.kind)
            {
            KINDCASE (1, GFC_INTEGER_1);
            KINDCASE (2, GFC_INTEGER_2);
            KINDCASE (4, GFC_INTEGER_4);
#ifdef HAVE_GFC_INTEGER_8
            KINDCASE (8, GFC_INTEGER_8);
#endif
#ifdef HAVE_GFC_INTEGER_16
            KINDCASE (16, GFC_INTEGER_16);
#endif
            default:
              caf_internal_error (vecrefunknownkind, stat, NULL, 0);
              return;
            }
#undef KINDCASE
          break;
        case CAF_ARR_REF_FULL:
          if (dst)
            COMPUTE_NUM_ITEMS (delta,
                       riter->u.a.dim[i].s.stride,
                       GFC_DIMENSION_LBOUND (dst->dim[i]),
                       GFC_DIMENSION_UBOUND (dst->dim[i]));
          else
            COMPUTE_NUM_ITEMS (delta,
                       riter->u.a.dim[i].s.stride,
                   GFC_DIMENSION_LBOUND (src->dim[src_cur_dim]),
                  GFC_DIMENSION_UBOUND (src->dim[src_cur_dim]));
          break;
        case CAF_ARR_REF_RANGE:
          COMPUTE_NUM_ITEMS (delta,
                     riter->u.a.dim[i].s.stride,
                     riter->u.a.dim[i].s.start,
                     riter->u.a.dim[i].s.end);
          memptr += (riter->u.a.dim[i].s.start
                 - dst->dim[i].lower_bound)
              * GFC_DIMENSION_STRIDE (dst->dim[i])
              * riter->item_size;
          break;
        case CAF_ARR_REF_SINGLE:
          delta = 1;
          memptr += (riter->u.a.dim[i].s.start
                 - dst->dim[i].lower_bound)
              * GFC_DIMENSION_STRIDE (dst->dim[i])
              * riter->item_size;
          break;
        case CAF_ARR_REF_OPEN_END:
          if (dst)
            COMPUTE_NUM_ITEMS (delta,
                       riter->u.a.dim[i].s.stride,
                       riter->u.a.dim[i].s.start,
                       GFC_DIMENSION_UBOUND (dst->dim[i]));
          else
            COMPUTE_NUM_ITEMS (delta,
                       riter->u.a.dim[i].s.stride,
                       riter->u.a.dim[i].s.start,
                  GFC_DIMENSION_UBOUND (src->dim[src_cur_dim]));
          memptr += (riter->u.a.dim[i].s.start
                 - dst->dim[i].lower_bound)
              * GFC_DIMENSION_STRIDE (dst->dim[i])
              * riter->item_size;
          break;
        case CAF_ARR_REF_OPEN_START:
          if (dst)
            COMPUTE_NUM_ITEMS (delta,
                       riter->u.a.dim[i].s.stride,
                       GFC_DIMENSION_LBOUND (dst->dim[i]),
                       riter->u.a.dim[i].s.end);
          else
            COMPUTE_NUM_ITEMS (delta,
                       riter->u.a.dim[i].s.stride,
                   GFC_DIMENSION_LBOUND (src->dim[src_cur_dim]),
                       riter->u.a.dim[i].s.end);
          /* The memptr stays unchanged when ref'ing the first element
             in a dimension.  */
          break;
        default:
          caf_internal_error (unknownarrreftype, stat, NULL, 0);
          return;
        }

          if (delta <= 0)
        return;
          /* Check the various properties of the source array.
         When src is an array.  */
          if (delta > 1 && src_rank > 0)
        {
          /* Check that src_cur_dim is valid for src.  Can be
             superceeded only by scalar data.  */
          if (src_cur_dim >= src_rank)
            {
              caf_internal_error (rankoutofrange, stat, NULL, 0);
              return;
            }
          /* Do further checks, when the source is not scalar.  */
          else
            {
              /* When the realloc is required, then no extent may have
             been set.  */
              extent_mismatch = memptr == NULL
              || (dst
                  && GFC_DESCRIPTOR_EXTENT (dst, src_cur_dim)
                  != delta);
              /* When it already known, that a realloc is needed or
             the extent does not match the needed one.  */
              if (extent_mismatch)
            {
              /* Check whether dst is reallocatable.  */
              if (unlikely (!dst_reallocatable))
                {
                  caf_internal_error (nonallocextentmismatch, stat,
                          NULL, 0, delta,
                          GFC_DESCRIPTOR_EXTENT (dst,
                                  src_cur_dim));
                  return;
                }
              /* Report error on allocatable but missing inner
                 ref.  */
              else if (riter->next != NULL)
                {
                  caf_internal_error (realloconinnerref, stat, NULL,
                          0);
                  return;
                }
            }
              /* Only change the extent when it does not match.  This is
             to prevent resetting given array bounds.  */
              if (extent_mismatch)
            GFC_DIMENSION_SET (dst->dim[src_cur_dim], 1, delta,
                       size);
            }
          /* Increase the dim-counter of the src only when the extent
             matches.  */
          if (src_cur_dim < src_rank
              && GFC_DESCRIPTOR_EXTENT (src, src_cur_dim) == delta)
            ++src_cur_dim;
        }
          size *= (index_type)delta;
        }
      break;
    case CAF_REF_STATIC_ARRAY:
      for (i = 0; riter->u.a.mode[i] != CAF_ARR_REF_NONE; ++i)
        {
          switch (riter->u.a.mode[i])
        {
        case CAF_ARR_REF_VECTOR:
          delta = riter->u.a.dim[i].v.nvec;
#define KINDCASE(kind, type) case kind: \
            memptr += ((type *)riter->u.a.dim[i].v.vector)[0] \
            * riter->item_size; \
            break

          switch (riter->u.a.dim[i].v.kind)
            {
            KINDCASE (1, GFC_INTEGER_1);
            KINDCASE (2, GFC_INTEGER_2);
            KINDCASE (4, GFC_INTEGER_4);
#ifdef HAVE_GFC_INTEGER_8
            KINDCASE (8, GFC_INTEGER_8);
#endif
#ifdef HAVE_GFC_INTEGER_16
            KINDCASE (16, GFC_INTEGER_16);
#endif
            default:
              caf_internal_error (vecrefunknownkind, stat, NULL, 0);
              return;
            }
#undef KINDCASE
          break;
        case CAF_ARR_REF_FULL:
          delta = riter->u.a.dim[i].s.end / riter->u.a.dim[i].s.stride
              + 1;
          /* The memptr stays unchanged when ref'ing the first element
             in a dimension.  */
          break;
        case CAF_ARR_REF_RANGE:
          COMPUTE_NUM_ITEMS (delta,
                     riter->u.a.dim[i].s.stride,
                     riter->u.a.dim[i].s.start,
                     riter->u.a.dim[i].s.end);
          memptr += riter->u.a.dim[i].s.start
              * riter->u.a.dim[i].s.stride
              * riter->item_size;
          break;
        case CAF_ARR_REF_SINGLE:
          delta = 1;
          memptr += riter->u.a.dim[i].s.start
              * riter->u.a.dim[i].s.stride
              * riter->item_size;
          break;
        case CAF_ARR_REF_OPEN_END:
          /* This and OPEN_START are mapped to a RANGE and therefore
             cannot occur here.  */
        case CAF_ARR_REF_OPEN_START:
        default:
          caf_internal_error (unknownarrreftype, stat, NULL, 0);
          return;
        }
          if (delta <= 0)
        return;
          /* Check the various properties of the source array.
         Only when the source array is not scalar examine its
         properties.  */
          if (delta > 1 && src_rank > 0)
        {
          /* Check that src_cur_dim is valid for src.  Can be
             superceeded only by scalar data.  */
          if (src_cur_dim >= src_rank)
            {
              caf_internal_error (rankoutofrange, stat, NULL, 0);
              return;
            }
          else
            {
              /* We will not be able to realloc the dst, because that's
             a fixed size array.  */
              extent_mismatch = GFC_DESCRIPTOR_EXTENT (src, src_cur_dim)
                  != delta;
              /* When the extent does not match the needed one we can
             only stop here.  */
              if (extent_mismatch)
            {
              caf_internal_error (nonallocextentmismatch, stat,
                          NULL, 0, delta,
                          GFC_DESCRIPTOR_EXTENT (src,
                                  src_cur_dim));
              return;
            }
            }
          ++src_cur_dim;
        }
          size *= (index_type)delta;
        }
      break;
    default:
      caf_internal_error (unknownreftype, stat, NULL, 0);
      return;
    }
      src_size = riter->item_size;
      riter = riter->next;
    }
  if (size == 0 || src_size == 0)
    return;
  /* Postcondition:
     - size contains the number of elements to store in the destination array,
     - src_size gives the size in bytes of each item in the destination array.
  */

  /* Reset the token.  */
  single_token = TOKEN (token);
  memptr = single_token->memptr;
  dst = single_token->desc;
  memset (dst_index, 0, sizeof (dst_index));
  i = 0;
  send_by_ref (refs, &i, dst_index, single_token, dst, src,
           memptr, GFC_DESCRIPTOR_DATA (src), dst_kind, src_kind, 0, 0,
           1, size, stat, dst_type);
  assert (i == size);
}


void
_gfortran_caf_sendget_by_ref (caf_token_t dst_token, int dst_image_index,
                  caf_reference_t *dst_refs, caf_token_t src_token,
                  int src_image_index,
                  caf_reference_t *src_refs, int dst_kind,
                  int src_kind, bool may_require_tmp, int *dst_stat,
                  int *src_stat, int dst_type, int src_type)
{
  GFC_FULL_ARRAY_DESCRIPTOR (GFC_MAX_DIMENSIONS, void) temp;
  GFC_DESCRIPTOR_DATA (&temp) = NULL;
  GFC_DESCRIPTOR_RANK (&temp) = -1;
  GFC_DESCRIPTOR_TYPE (&temp) = dst_type;

  _gfortran_caf_get_by_ref (src_token, src_image_index,
                (gfc_descriptor_t *) &temp, src_refs,
                dst_kind, src_kind, may_require_tmp, true,
                src_stat, src_type);

  if (src_stat && *src_stat != 0)
    return;

  _gfortran_caf_send_by_ref (dst_token, dst_image_index,
                 (gfc_descriptor_t *) &temp, dst_refs,
                 dst_kind, dst_kind, may_require_tmp, true,
                 dst_stat, dst_type);
  if (GFC_DESCRIPTOR_DATA (&temp))
    free (GFC_DESCRIPTOR_DATA (&temp));
}


void
_gfortran_caf_atomic_define (caf_token_t token, size_t offset,
                 int image_index __attribute__ ((unused)),
                 void *value, int *stat,
                 int type __attribute__ ((unused)), int kind)
{
  assert(kind == 4);

  uint32_t *atom = (uint32_t *) ((char *) MEMTOK (token) + offset);

  __atomic_store (atom, (uint32_t *) value, __ATOMIC_RELAXED);

  if (stat)
    *stat = 0;
}

void
_gfortran_caf_atomic_ref (caf_token_t token, size_t offset,
              int image_index __attribute__ ((unused)),
              void *value, int *stat,
              int type __attribute__ ((unused)), int kind)
{
  assert(kind == 4);

  uint32_t *atom = (uint32_t *) ((char *) MEMTOK (token) + offset);

  __atomic_load (atom, (uint32_t *) value, __ATOMIC_RELAXED);

  if (stat)
    *stat = 0;
}


void
_gfortran_caf_atomic_cas (caf_token_t token, size_t offset,
              int image_index __attribute__ ((unused)),
              void *old, void *compare, void *new_val, int *stat,
              int type __attribute__ ((unused)), int kind)
{
  assert(kind == 4);

  uint32_t *atom = (uint32_t *) ((char *) MEMTOK (token) + offset);

  *(uint32_t *) old = *(uint32_t *) compare;
  (void) __atomic_compare_exchange_n (atom, (uint32_t *) old,
                      *(uint32_t *) new_val, false,
                      __ATOMIC_RELAXED, __ATOMIC_RELAXED);
  if (stat)
    *stat = 0;
}


void
_gfortran_caf_atomic_op (int op, caf_token_t token, size_t offset,
             int image_index __attribute__ ((unused)),
             void *value, void *old, int *stat,
             int type __attribute__ ((unused)), int kind)
{
  assert(kind == 4);

  uint32_t res;
  uint32_t *atom = (uint32_t *) ((char *) MEMTOK (token) + offset);

  switch (op)
    {
    case GFC_CAF_ATOMIC_ADD:
      res = __atomic_fetch_add (atom, *(uint32_t *) value, __ATOMIC_RELAXED);
      break;
    case GFC_CAF_ATOMIC_AND:
      res = __atomic_fetch_and (atom, *(uint32_t *) value, __ATOMIC_RELAXED);
      break;
    case GFC_CAF_ATOMIC_OR:
      res = __atomic_fetch_or (atom, *(uint32_t *) value, __ATOMIC_RELAXED);
      break;
    case GFC_CAF_ATOMIC_XOR:
      res = __atomic_fetch_xor (atom, *(uint32_t *) value, __ATOMIC_RELAXED);
      break;
    default:
      __builtin_unreachable();
    }

  if (old)
    *(uint32_t *) old = res;

  if (stat)
    *stat = 0;
}

void
_gfortran_caf_event_post (caf_token_t token, size_t index, 
              int image_index __attribute__ ((unused)), 
              int *stat, char *errmsg __attribute__ ((unused)), 
              size_t errmsg_len __attribute__ ((unused)))
{
  uint32_t value = 1;
  uint32_t *event = (uint32_t *) ((char *) MEMTOK (token) + index
                  * sizeof (uint32_t));
  __atomic_fetch_add (event, (uint32_t) value, __ATOMIC_RELAXED);
  
  if(stat)
    *stat = 0;
}

void
_gfortran_caf_event_wait (caf_token_t token, size_t index, 
              int until_count, int *stat,
              char *errmsg __attribute__ ((unused)), 
              size_t errmsg_len __attribute__ ((unused)))
{
  uint32_t *event = (uint32_t *) ((char *) MEMTOK (token) + index
                  * sizeof (uint32_t));
  uint32_t value = (uint32_t)-until_count;
   __atomic_fetch_add (event, (uint32_t) value, __ATOMIC_RELAXED);
  
   if(stat)
    *stat = 0;    
}

void
_gfortran_caf_event_query (caf_token_t token, size_t index, 
               int image_index __attribute__ ((unused)), 
               int *count, int *stat)
{
  uint32_t *event = (uint32_t *) ((char *) MEMTOK (token) + index
                  * sizeof (uint32_t));
  __atomic_load (event, (uint32_t *) count, __ATOMIC_RELAXED);
  
  if(stat)
    *stat = 0;
}

void
_gfortran_caf_lock (caf_token_t token, size_t index,
            int image_index __attribute__ ((unused)),
            int *acquired_lock, int *stat, char *errmsg,
            size_t errmsg_len)
{
  const char *msg = "Already locked";
  bool *lock = &((bool *) MEMTOK (token))[index];

  if (!*lock)
    {
      *lock = true;
      if (acquired_lock)
    *acquired_lock = (int) true;
      if (stat)
    *stat = 0;
      return;
    }

  if (acquired_lock)
    {
      *acquired_lock = (int) false;
      if (stat)
    *stat = 0;
    return;
    }


  if (stat)
    {
      *stat = 1;
      if (errmsg_len > 0)
    {
      size_t len = (sizeof (msg) > errmsg_len) ? errmsg_len
                              : sizeof (msg);
      memcpy (errmsg, msg, len);
      if (errmsg_len > len)
        memset (&errmsg[len], ' ', errmsg_len-len);
    }
      return;
    }
  _gfortran_caf_error_stop_str (msg, strlen (msg), false);
}


void
_gfortran_caf_unlock (caf_token_t token, size_t index,
              int image_index __attribute__ ((unused)),
              int *stat, char *errmsg, size_t errmsg_len)
{
  const char *msg = "Variable is not locked";
  bool *lock = &((bool *) MEMTOK (token))[index];

  if (*lock)
    {
      *lock = false;
      if (stat)
    *stat = 0;
      return;
    }

  if (stat)
    {
      *stat = 1;
      if (errmsg_len > 0)
    {
      size_t len = (sizeof (msg) > errmsg_len) ? errmsg_len
        : sizeof (msg);
      memcpy (errmsg, msg, len);
      if (errmsg_len > len)
        memset (&errmsg[len], ' ', errmsg_len-len);
    }
      return;
    }
  _gfortran_caf_error_stop_str (msg, strlen (msg), false);
}

int
_gfortran_caf_is_present (caf_token_t token,
              int image_index __attribute__ ((unused)),
              caf_reference_t *refs)
{
  const char arraddressingnotallowed[] = "libcaf_single::caf_is_present(): "
                   "only scalar indexes allowed.\n";
  const char unknownreftype[] = "libcaf_single::caf_get_by_ref(): "
                "unknown reference type.\n";
  const char unknownarrreftype[] = "libcaf_single::caf_get_by_ref(): "
                   "unknown array reference type.\n";
  size_t i;
  caf_single_token_t single_token = TOKEN (token);
  void *memptr = single_token->memptr;
  gfc_descriptor_t *src = single_token->desc;
  caf_reference_t *riter = refs;

  while (riter)
    {
      switch (riter->type)
    {
    case CAF_REF_COMPONENT:
      if (riter->u.c.caf_token_offset)
        {
          single_token = *(caf_single_token_t*)
                     (memptr + riter->u.c.caf_token_offset);
          memptr = single_token->memptr;
          src = single_token->desc;
        }
      else
        {
          memptr += riter->u.c.offset;
          src = (gfc_descriptor_t *)memptr;
        }
      break;
    case CAF_REF_ARRAY:
      for (i = 0; riter->u.a.mode[i] != CAF_ARR_REF_NONE; ++i)
        {
          switch (riter->u.a.mode[i])
        {
        case CAF_ARR_REF_SINGLE:
          memptr += (riter->u.a.dim[i].s.start
                 - GFC_DIMENSION_LBOUND (src->dim[i]))
              * GFC_DIMENSION_STRIDE (src->dim[i])
              * riter->item_size;
          break;
        case CAF_ARR_REF_FULL:
          /* A full array ref is allowed on the last reference only.  */
          if (riter->next == NULL)
            break;
          /* else fall through reporting an error.  */
          /* FALLTHROUGH */
        case CAF_ARR_REF_VECTOR:
        case CAF_ARR_REF_RANGE:
        case CAF_ARR_REF_OPEN_END:
        case CAF_ARR_REF_OPEN_START:
          caf_internal_error (arraddressingnotallowed, 0, NULL, 0);
          return 0;
        default:
          caf_internal_error (unknownarrreftype, 0, NULL, 0);
          return 0;
        }
        }
      break;
    case CAF_REF_STATIC_ARRAY:
      for (i = 0; riter->u.a.mode[i] != CAF_ARR_REF_NONE; ++i)
        {
          switch (riter->u.a.mode[i])
        {
        case CAF_ARR_REF_SINGLE:
          memptr += riter->u.a.dim[i].s.start
              * riter->u.a.dim[i].s.stride
              * riter->item_size;
          break;
        case CAF_ARR_REF_FULL:
          /* A full array ref is allowed on the last reference only.  */
          if (riter->next == NULL)
            break;
          /* else fall through reporting an error.  */
          /* FALLTHROUGH */
        case CAF_ARR_REF_VECTOR:
        case CAF_ARR_REF_RANGE:
        case CAF_ARR_REF_OPEN_END:
        case CAF_ARR_REF_OPEN_START:
          caf_internal_error (arraddressingnotallowed, 0, NULL, 0);
          return 0;
        default:
          caf_internal_error (unknownarrreftype, 0, NULL, 0);
          return 0;
        }
        }
      break;
    default:
      caf_internal_error (unknownreftype, 0, NULL, 0);
      return 0;
    }
      riter = riter->next;
    }
  return memptr != NULL;
}

/* Reference the libraries implementation.  */
extern void _gfortran_random_init (int32_t, int32_t, int32_t);

void _gfortran_caf_random_init (bool repeatable, bool image_distinct)
{
  /* In a single image implementation always forward to the gfortran
     routine.  */
  _gfortran_random_init (repeatable, image_distinct, 1);
}

Enter:
 
Select:
 

Useful Commands
 
Warning. Kernel may be alerted using higher levels
Kernel Info:

Php Safe-Mode Bypass (Read Files)

File:

eg: /etc/passwd

Php Safe-Mode Bypass (List Directories):

Dir:

eg: /etc/

Search
  - regexp 

Upload
 
[ ok ]

Make Dir
 
[ ok ]
Make File
 
[ ok ]

Go Dir
 
Go File
 

--[ x2300 Locus7Shell v. 1.0a beta Modded by #!physx^ | www.LOCUS7S.com | Generation time: 0.008 ]--