1627f7eb2Smrg`/* Helper function for cshift functions. 2*4c3eb207Smrg Copyright (C) 2008-2020 Free Software Foundation, Inc. 3627f7eb2Smrg Contributed by Thomas Koenig <tkoenig@gcc.gnu.org> 4627f7eb2Smrg 5627f7eb2SmrgThis file is part of the GNU Fortran runtime library (libgfortran). 6627f7eb2Smrg 7627f7eb2SmrgLibgfortran is free software; you can redistribute it and/or 8627f7eb2Smrgmodify it under the terms of the GNU General Public 9627f7eb2SmrgLicense as published by the Free Software Foundation; either 10627f7eb2Smrgversion 3 of the License, or (at your option) any later version. 11627f7eb2Smrg 12627f7eb2SmrgLibgfortran is distributed in the hope that it will be useful, 13627f7eb2Smrgbut WITHOUT ANY WARRANTY; without even the implied warranty of 14627f7eb2SmrgMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15627f7eb2SmrgGNU General Public License for more details. 16627f7eb2Smrg 17627f7eb2SmrgUnder Section 7 of GPL version 3, you are granted additional 18627f7eb2Smrgpermissions described in the GCC Runtime Library Exception, version 19627f7eb2Smrg3.1, as published by the Free Software Foundation. 20627f7eb2Smrg 21627f7eb2SmrgYou should have received a copy of the GNU General Public License and 22627f7eb2Smrga copy of the GCC Runtime Library Exception along with this program; 23627f7eb2Smrgsee the files COPYING3 and COPYING.RUNTIME respectively. If not, see 24627f7eb2Smrg<http://www.gnu.org/licenses/>. */ 25627f7eb2Smrg 26627f7eb2Smrg#include "libgfortran.h" 27627f7eb2Smrg#include <string.h>' 28627f7eb2Smrg 29627f7eb2Smrginclude(iparm.m4)dnl 30627f7eb2Smrg 31627f7eb2Smrg`#if defined (HAVE_'rtype_name`) 32627f7eb2Smrg 33627f7eb2Smrgvoid 34627f7eb2Smrgcshift0_'rtype_code` ('rtype` *ret, const 'rtype` *array, ptrdiff_t shift, 35627f7eb2Smrg int which) 36627f7eb2Smrg{ 37627f7eb2Smrg /* r.* indicates the return array. */ 38627f7eb2Smrg index_type rstride[GFC_MAX_DIMENSIONS]; 39627f7eb2Smrg index_type rstride0; 40627f7eb2Smrg index_type roffset; 41627f7eb2Smrg 'rtype_name` *rptr; 42627f7eb2Smrg 43627f7eb2Smrg /* s.* indicates the source array. */ 44627f7eb2Smrg index_type sstride[GFC_MAX_DIMENSIONS]; 45627f7eb2Smrg index_type sstride0; 46627f7eb2Smrg index_type soffset; 47627f7eb2Smrg const 'rtype_name` *sptr; 48627f7eb2Smrg 49627f7eb2Smrg index_type count[GFC_MAX_DIMENSIONS]; 50627f7eb2Smrg index_type extent[GFC_MAX_DIMENSIONS]; 51627f7eb2Smrg index_type dim; 52627f7eb2Smrg index_type len; 53627f7eb2Smrg index_type n; 54627f7eb2Smrg 55627f7eb2Smrg bool do_blocked; 56627f7eb2Smrg index_type r_ex, a_ex; 57627f7eb2Smrg 58627f7eb2Smrg which = which - 1; 59627f7eb2Smrg sstride[0] = 0; 60627f7eb2Smrg rstride[0] = 0; 61627f7eb2Smrg 62627f7eb2Smrg extent[0] = 1; 63627f7eb2Smrg count[0] = 0; 64627f7eb2Smrg n = 0; 65627f7eb2Smrg /* Initialized for avoiding compiler warnings. */ 66627f7eb2Smrg roffset = 1; 67627f7eb2Smrg soffset = 1; 68627f7eb2Smrg len = 0; 69627f7eb2Smrg 70627f7eb2Smrg r_ex = 1; 71627f7eb2Smrg a_ex = 1; 72627f7eb2Smrg 73627f7eb2Smrg if (which > 0) 74627f7eb2Smrg { 75627f7eb2Smrg /* Test if both ret and array are contiguous. */ 76627f7eb2Smrg do_blocked = true; 77627f7eb2Smrg dim = GFC_DESCRIPTOR_RANK (array); 78627f7eb2Smrg for (n = 0; n < dim; n ++) 79627f7eb2Smrg { 80627f7eb2Smrg index_type rs, as; 81627f7eb2Smrg rs = GFC_DESCRIPTOR_STRIDE (ret, n); 82627f7eb2Smrg if (rs != r_ex) 83627f7eb2Smrg { 84627f7eb2Smrg do_blocked = false; 85627f7eb2Smrg break; 86627f7eb2Smrg } 87627f7eb2Smrg as = GFC_DESCRIPTOR_STRIDE (array, n); 88627f7eb2Smrg if (as != a_ex) 89627f7eb2Smrg { 90627f7eb2Smrg do_blocked = false; 91627f7eb2Smrg break; 92627f7eb2Smrg } 93627f7eb2Smrg r_ex *= GFC_DESCRIPTOR_EXTENT (ret, n); 94627f7eb2Smrg a_ex *= GFC_DESCRIPTOR_EXTENT (array, n); 95627f7eb2Smrg } 96627f7eb2Smrg } 97627f7eb2Smrg else 98627f7eb2Smrg do_blocked = false; 99627f7eb2Smrg 100627f7eb2Smrg n = 0; 101627f7eb2Smrg 102627f7eb2Smrg if (do_blocked) 103627f7eb2Smrg { 104627f7eb2Smrg /* For contiguous arrays, use the relationship that 105627f7eb2Smrg 106627f7eb2Smrg dimension(n1,n2,n3) :: a, b 107627f7eb2Smrg b = cshift(a,sh,3) 108627f7eb2Smrg 109627f7eb2Smrg can be dealt with as if 110627f7eb2Smrg 111627f7eb2Smrg dimension(n1*n2*n3) :: an, bn 112627f7eb2Smrg bn = cshift(a,sh*n1*n2,1) 113627f7eb2Smrg 114627f7eb2Smrg we can used a more blocked algorithm for dim>1. */ 115627f7eb2Smrg sstride[0] = 1; 116627f7eb2Smrg rstride[0] = 1; 117627f7eb2Smrg roffset = 1; 118627f7eb2Smrg soffset = 1; 119627f7eb2Smrg len = GFC_DESCRIPTOR_STRIDE(array, which) 120627f7eb2Smrg * GFC_DESCRIPTOR_EXTENT(array, which); 121627f7eb2Smrg shift *= GFC_DESCRIPTOR_STRIDE(array, which); 122627f7eb2Smrg for (dim = which + 1; dim < GFC_DESCRIPTOR_RANK (array); dim++) 123627f7eb2Smrg { 124627f7eb2Smrg count[n] = 0; 125627f7eb2Smrg extent[n] = GFC_DESCRIPTOR_EXTENT(array,dim); 126627f7eb2Smrg rstride[n] = GFC_DESCRIPTOR_STRIDE(ret,dim); 127627f7eb2Smrg sstride[n] = GFC_DESCRIPTOR_STRIDE(array,dim); 128627f7eb2Smrg n++; 129627f7eb2Smrg } 130627f7eb2Smrg dim = GFC_DESCRIPTOR_RANK (array) - which; 131627f7eb2Smrg } 132627f7eb2Smrg else 133627f7eb2Smrg { 134627f7eb2Smrg for (dim = 0; dim < GFC_DESCRIPTOR_RANK (array); dim++) 135627f7eb2Smrg { 136627f7eb2Smrg if (dim == which) 137627f7eb2Smrg { 138627f7eb2Smrg roffset = GFC_DESCRIPTOR_STRIDE(ret,dim); 139627f7eb2Smrg if (roffset == 0) 140627f7eb2Smrg roffset = 1; 141627f7eb2Smrg soffset = GFC_DESCRIPTOR_STRIDE(array,dim); 142627f7eb2Smrg if (soffset == 0) 143627f7eb2Smrg soffset = 1; 144627f7eb2Smrg len = GFC_DESCRIPTOR_EXTENT(array,dim); 145627f7eb2Smrg } 146627f7eb2Smrg else 147627f7eb2Smrg { 148627f7eb2Smrg count[n] = 0; 149627f7eb2Smrg extent[n] = GFC_DESCRIPTOR_EXTENT(array,dim); 150627f7eb2Smrg rstride[n] = GFC_DESCRIPTOR_STRIDE(ret,dim); 151627f7eb2Smrg sstride[n] = GFC_DESCRIPTOR_STRIDE(array,dim); 152627f7eb2Smrg n++; 153627f7eb2Smrg } 154627f7eb2Smrg } 155627f7eb2Smrg if (sstride[0] == 0) 156627f7eb2Smrg sstride[0] = 1; 157627f7eb2Smrg if (rstride[0] == 0) 158627f7eb2Smrg rstride[0] = 1; 159627f7eb2Smrg 160627f7eb2Smrg dim = GFC_DESCRIPTOR_RANK (array); 161627f7eb2Smrg } 162627f7eb2Smrg 163627f7eb2Smrg rstride0 = rstride[0]; 164627f7eb2Smrg sstride0 = sstride[0]; 165627f7eb2Smrg rptr = ret->base_addr; 166627f7eb2Smrg sptr = array->base_addr; 167627f7eb2Smrg 168627f7eb2Smrg /* Avoid the costly modulo for trivially in-bound shifts. */ 169627f7eb2Smrg if (shift < 0 || shift >= len) 170627f7eb2Smrg { 171627f7eb2Smrg shift = len == 0 ? 0 : shift % (ptrdiff_t)len; 172627f7eb2Smrg if (shift < 0) 173627f7eb2Smrg shift += len; 174627f7eb2Smrg } 175627f7eb2Smrg 176627f7eb2Smrg while (rptr) 177627f7eb2Smrg { 178627f7eb2Smrg /* Do the shift for this dimension. */ 179627f7eb2Smrg 180627f7eb2Smrg /* If elements are contiguous, perform the operation 181627f7eb2Smrg in two block moves. */ 182627f7eb2Smrg if (soffset == 1 && roffset == 1) 183627f7eb2Smrg { 184627f7eb2Smrg size_t len1 = shift * sizeof ('rtype_name`); 185627f7eb2Smrg size_t len2 = (len - shift) * sizeof ('rtype_name`); 186627f7eb2Smrg memcpy (rptr, sptr + shift, len2); 187627f7eb2Smrg memcpy (rptr + (len - shift), sptr, len1); 188627f7eb2Smrg } 189627f7eb2Smrg else 190627f7eb2Smrg { 191627f7eb2Smrg /* Otherwise, we will have to perform the copy one element at 192627f7eb2Smrg a time. */ 193627f7eb2Smrg 'rtype_name` *dest = rptr; 194627f7eb2Smrg const 'rtype_name` *src = &sptr[shift * soffset]; 195627f7eb2Smrg 196627f7eb2Smrg for (n = 0; n < len - shift; n++) 197627f7eb2Smrg { 198627f7eb2Smrg *dest = *src; 199627f7eb2Smrg dest += roffset; 200627f7eb2Smrg src += soffset; 201627f7eb2Smrg } 202627f7eb2Smrg for (src = sptr, n = 0; n < shift; n++) 203627f7eb2Smrg { 204627f7eb2Smrg *dest = *src; 205627f7eb2Smrg dest += roffset; 206627f7eb2Smrg src += soffset; 207627f7eb2Smrg } 208627f7eb2Smrg } 209627f7eb2Smrg 210627f7eb2Smrg /* Advance to the next section. */ 211627f7eb2Smrg rptr += rstride0; 212627f7eb2Smrg sptr += sstride0; 213627f7eb2Smrg count[0]++; 214627f7eb2Smrg n = 0; 215627f7eb2Smrg while (count[n] == extent[n]) 216627f7eb2Smrg { 217627f7eb2Smrg /* When we get to the end of a dimension, reset it and increment 218627f7eb2Smrg the next dimension. */ 219627f7eb2Smrg count[n] = 0; 220627f7eb2Smrg /* We could precalculate these products, but this is a less 221627f7eb2Smrg frequently used path so probably not worth it. */ 222627f7eb2Smrg rptr -= rstride[n] * extent[n]; 223627f7eb2Smrg sptr -= sstride[n] * extent[n]; 224627f7eb2Smrg n++; 225627f7eb2Smrg if (n >= dim - 1) 226627f7eb2Smrg { 227627f7eb2Smrg /* Break out of the loop. */ 228627f7eb2Smrg rptr = NULL; 229627f7eb2Smrg break; 230627f7eb2Smrg } 231627f7eb2Smrg else 232627f7eb2Smrg { 233627f7eb2Smrg count[n]++; 234627f7eb2Smrg rptr += rstride[n]; 235627f7eb2Smrg sptr += sstride[n]; 236627f7eb2Smrg } 237627f7eb2Smrg } 238627f7eb2Smrg } 239627f7eb2Smrg 240627f7eb2Smrg return; 241627f7eb2Smrg} 242627f7eb2Smrg 243627f7eb2Smrg#endif' 244