1 1.1 mrg `/* Helper function for cshift functions. 2 1.1.1.4 mrg Copyright (C) 2008-2024 Free Software Foundation, Inc. 3 1.1 mrg Contributed by Thomas Koenig <tkoenig (a] gcc.gnu.org> 4 1.1 mrg 5 1.1 mrg This file is part of the GNU Fortran runtime library (libgfortran). 6 1.1 mrg 7 1.1 mrg Libgfortran is free software; you can redistribute it and/or 8 1.1 mrg modify it under the terms of the GNU General Public 9 1.1 mrg License as published by the Free Software Foundation; either 10 1.1 mrg version 3 of the License, or (at your option) any later version. 11 1.1 mrg 12 1.1 mrg Libgfortran is distributed in the hope that it will be useful, 13 1.1 mrg but WITHOUT ANY WARRANTY; without even the implied warranty of 14 1.1 mrg MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 1.1 mrg GNU General Public License for more details. 16 1.1 mrg 17 1.1 mrg Under Section 7 of GPL version 3, you are granted additional 18 1.1 mrg permissions described in the GCC Runtime Library Exception, version 19 1.1 mrg 3.1, as published by the Free Software Foundation. 20 1.1 mrg 21 1.1 mrg You should have received a copy of the GNU General Public License and 22 1.1 mrg a copy of the GCC Runtime Library Exception along with this program; 23 1.1 mrg see the files COPYING3 and COPYING.RUNTIME respectively. If not, see 24 1.1 mrg <http://www.gnu.org/licenses/>. */ 25 1.1 mrg 26 1.1 mrg #include "libgfortran.h" 27 1.1 mrg #include <string.h>' 28 1.1 mrg 29 1.1 mrg include(iparm.m4)dnl 30 1.1 mrg 31 1.1 mrg `#if defined (HAVE_'rtype_name`) 32 1.1 mrg 33 1.1 mrg void 34 1.1 mrg cshift0_'rtype_code` ('rtype` *ret, const 'rtype` *array, ptrdiff_t shift, 35 1.1 mrg int which) 36 1.1 mrg { 37 1.1 mrg /* r.* indicates the return array. */ 38 1.1 mrg index_type rstride[GFC_MAX_DIMENSIONS]; 39 1.1 mrg index_type rstride0; 40 1.1 mrg index_type roffset; 41 1.1 mrg 'rtype_name` *rptr; 42 1.1 mrg 43 1.1 mrg /* s.* indicates the source array. */ 44 1.1 mrg index_type sstride[GFC_MAX_DIMENSIONS]; 45 1.1 mrg index_type sstride0; 46 1.1 mrg index_type soffset; 47 1.1 mrg const 'rtype_name` *sptr; 48 1.1 mrg 49 1.1 mrg index_type count[GFC_MAX_DIMENSIONS]; 50 1.1 mrg index_type extent[GFC_MAX_DIMENSIONS]; 51 1.1 mrg index_type dim; 52 1.1 mrg index_type len; 53 1.1 mrg index_type n; 54 1.1 mrg 55 1.1 mrg bool do_blocked; 56 1.1 mrg index_type r_ex, a_ex; 57 1.1 mrg 58 1.1 mrg which = which - 1; 59 1.1 mrg sstride[0] = 0; 60 1.1 mrg rstride[0] = 0; 61 1.1 mrg 62 1.1 mrg extent[0] = 1; 63 1.1 mrg count[0] = 0; 64 1.1 mrg n = 0; 65 1.1 mrg /* Initialized for avoiding compiler warnings. */ 66 1.1 mrg roffset = 1; 67 1.1 mrg soffset = 1; 68 1.1 mrg len = 0; 69 1.1 mrg 70 1.1 mrg r_ex = 1; 71 1.1 mrg a_ex = 1; 72 1.1 mrg 73 1.1 mrg if (which > 0) 74 1.1 mrg { 75 1.1 mrg /* Test if both ret and array are contiguous. */ 76 1.1 mrg do_blocked = true; 77 1.1 mrg dim = GFC_DESCRIPTOR_RANK (array); 78 1.1 mrg for (n = 0; n < dim; n ++) 79 1.1 mrg { 80 1.1 mrg index_type rs, as; 81 1.1 mrg rs = GFC_DESCRIPTOR_STRIDE (ret, n); 82 1.1 mrg if (rs != r_ex) 83 1.1 mrg { 84 1.1 mrg do_blocked = false; 85 1.1 mrg break; 86 1.1 mrg } 87 1.1 mrg as = GFC_DESCRIPTOR_STRIDE (array, n); 88 1.1 mrg if (as != a_ex) 89 1.1 mrg { 90 1.1 mrg do_blocked = false; 91 1.1 mrg break; 92 1.1 mrg } 93 1.1 mrg r_ex *= GFC_DESCRIPTOR_EXTENT (ret, n); 94 1.1 mrg a_ex *= GFC_DESCRIPTOR_EXTENT (array, n); 95 1.1 mrg } 96 1.1 mrg } 97 1.1 mrg else 98 1.1 mrg do_blocked = false; 99 1.1 mrg 100 1.1 mrg n = 0; 101 1.1 mrg 102 1.1 mrg if (do_blocked) 103 1.1 mrg { 104 1.1 mrg /* For contiguous arrays, use the relationship that 105 1.1 mrg 106 1.1 mrg dimension(n1,n2,n3) :: a, b 107 1.1 mrg b = cshift(a,sh,3) 108 1.1 mrg 109 1.1 mrg can be dealt with as if 110 1.1 mrg 111 1.1 mrg dimension(n1*n2*n3) :: an, bn 112 1.1 mrg bn = cshift(a,sh*n1*n2,1) 113 1.1 mrg 114 1.1 mrg we can used a more blocked algorithm for dim>1. */ 115 1.1 mrg sstride[0] = 1; 116 1.1 mrg rstride[0] = 1; 117 1.1 mrg roffset = 1; 118 1.1 mrg soffset = 1; 119 1.1 mrg len = GFC_DESCRIPTOR_STRIDE(array, which) 120 1.1 mrg * GFC_DESCRIPTOR_EXTENT(array, which); 121 1.1 mrg shift *= GFC_DESCRIPTOR_STRIDE(array, which); 122 1.1 mrg for (dim = which + 1; dim < GFC_DESCRIPTOR_RANK (array); dim++) 123 1.1 mrg { 124 1.1 mrg count[n] = 0; 125 1.1 mrg extent[n] = GFC_DESCRIPTOR_EXTENT(array,dim); 126 1.1 mrg rstride[n] = GFC_DESCRIPTOR_STRIDE(ret,dim); 127 1.1 mrg sstride[n] = GFC_DESCRIPTOR_STRIDE(array,dim); 128 1.1 mrg n++; 129 1.1 mrg } 130 1.1 mrg dim = GFC_DESCRIPTOR_RANK (array) - which; 131 1.1 mrg } 132 1.1 mrg else 133 1.1 mrg { 134 1.1 mrg for (dim = 0; dim < GFC_DESCRIPTOR_RANK (array); dim++) 135 1.1 mrg { 136 1.1 mrg if (dim == which) 137 1.1 mrg { 138 1.1 mrg roffset = GFC_DESCRIPTOR_STRIDE(ret,dim); 139 1.1 mrg if (roffset == 0) 140 1.1 mrg roffset = 1; 141 1.1 mrg soffset = GFC_DESCRIPTOR_STRIDE(array,dim); 142 1.1 mrg if (soffset == 0) 143 1.1 mrg soffset = 1; 144 1.1 mrg len = GFC_DESCRIPTOR_EXTENT(array,dim); 145 1.1 mrg } 146 1.1 mrg else 147 1.1 mrg { 148 1.1 mrg count[n] = 0; 149 1.1 mrg extent[n] = GFC_DESCRIPTOR_EXTENT(array,dim); 150 1.1 mrg rstride[n] = GFC_DESCRIPTOR_STRIDE(ret,dim); 151 1.1 mrg sstride[n] = GFC_DESCRIPTOR_STRIDE(array,dim); 152 1.1 mrg n++; 153 1.1 mrg } 154 1.1 mrg } 155 1.1 mrg if (sstride[0] == 0) 156 1.1 mrg sstride[0] = 1; 157 1.1 mrg if (rstride[0] == 0) 158 1.1 mrg rstride[0] = 1; 159 1.1 mrg 160 1.1 mrg dim = GFC_DESCRIPTOR_RANK (array); 161 1.1 mrg } 162 1.1 mrg 163 1.1 mrg rstride0 = rstride[0]; 164 1.1 mrg sstride0 = sstride[0]; 165 1.1 mrg rptr = ret->base_addr; 166 1.1 mrg sptr = array->base_addr; 167 1.1 mrg 168 1.1 mrg /* Avoid the costly modulo for trivially in-bound shifts. */ 169 1.1 mrg if (shift < 0 || shift >= len) 170 1.1 mrg { 171 1.1 mrg shift = len == 0 ? 0 : shift % (ptrdiff_t)len; 172 1.1 mrg if (shift < 0) 173 1.1 mrg shift += len; 174 1.1 mrg } 175 1.1 mrg 176 1.1 mrg while (rptr) 177 1.1 mrg { 178 1.1 mrg /* Do the shift for this dimension. */ 179 1.1 mrg 180 1.1 mrg /* If elements are contiguous, perform the operation 181 1.1 mrg in two block moves. */ 182 1.1 mrg if (soffset == 1 && roffset == 1) 183 1.1 mrg { 184 1.1 mrg size_t len1 = shift * sizeof ('rtype_name`); 185 1.1 mrg size_t len2 = (len - shift) * sizeof ('rtype_name`); 186 1.1 mrg memcpy (rptr, sptr + shift, len2); 187 1.1 mrg memcpy (rptr + (len - shift), sptr, len1); 188 1.1 mrg } 189 1.1 mrg else 190 1.1 mrg { 191 1.1 mrg /* Otherwise, we will have to perform the copy one element at 192 1.1 mrg a time. */ 193 1.1 mrg 'rtype_name` *dest = rptr; 194 1.1 mrg const 'rtype_name` *src = &sptr[shift * soffset]; 195 1.1 mrg 196 1.1 mrg for (n = 0; n < len - shift; n++) 197 1.1 mrg { 198 1.1 mrg *dest = *src; 199 1.1 mrg dest += roffset; 200 1.1 mrg src += soffset; 201 1.1 mrg } 202 1.1 mrg for (src = sptr, n = 0; n < shift; n++) 203 1.1 mrg { 204 1.1 mrg *dest = *src; 205 1.1 mrg dest += roffset; 206 1.1 mrg src += soffset; 207 1.1 mrg } 208 1.1 mrg } 209 1.1 mrg 210 1.1 mrg /* Advance to the next section. */ 211 1.1 mrg rptr += rstride0; 212 1.1 mrg sptr += sstride0; 213 1.1 mrg count[0]++; 214 1.1 mrg n = 0; 215 1.1 mrg while (count[n] == extent[n]) 216 1.1 mrg { 217 1.1 mrg /* When we get to the end of a dimension, reset it and increment 218 1.1 mrg the next dimension. */ 219 1.1 mrg count[n] = 0; 220 1.1 mrg /* We could precalculate these products, but this is a less 221 1.1 mrg frequently used path so probably not worth it. */ 222 1.1 mrg rptr -= rstride[n] * extent[n]; 223 1.1 mrg sptr -= sstride[n] * extent[n]; 224 1.1 mrg n++; 225 1.1 mrg if (n >= dim - 1) 226 1.1 mrg { 227 1.1 mrg /* Break out of the loop. */ 228 1.1 mrg rptr = NULL; 229 1.1 mrg break; 230 1.1 mrg } 231 1.1 mrg else 232 1.1 mrg { 233 1.1 mrg count[n]++; 234 1.1 mrg rptr += rstride[n]; 235 1.1 mrg sptr += sstride[n]; 236 1.1 mrg } 237 1.1 mrg } 238 1.1 mrg } 239 1.1 mrg 240 1.1 mrg return; 241 1.1 mrg } 242 1.1 mrg 243 1.1 mrg #endif' 244