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 (at) 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 30 1.1 mrg #if defined (HAVE_GFC_COMPLEX_10) 31 1.1 mrg 32 1.1 mrg void 33 1.1 mrg cshift0_c10 (gfc_array_c10 *ret, const gfc_array_c10 *array, ptrdiff_t shift, 34 1.1 mrg int which) 35 1.1 mrg { 36 1.1 mrg /* r.* indicates the return array. */ 37 1.1 mrg index_type rstride[GFC_MAX_DIMENSIONS]; 38 1.1 mrg index_type rstride0; 39 1.1 mrg index_type roffset; 40 1.1 mrg GFC_COMPLEX_10 *rptr; 41 1.1 mrg 42 1.1 mrg /* s.* indicates the source array. */ 43 1.1 mrg index_type sstride[GFC_MAX_DIMENSIONS]; 44 1.1 mrg index_type sstride0; 45 1.1 mrg index_type soffset; 46 1.1 mrg const GFC_COMPLEX_10 *sptr; 47 1.1 mrg 48 1.1 mrg index_type count[GFC_MAX_DIMENSIONS]; 49 1.1 mrg index_type extent[GFC_MAX_DIMENSIONS]; 50 1.1 mrg index_type dim; 51 1.1 mrg index_type len; 52 1.1 mrg index_type n; 53 1.1 mrg 54 1.1 mrg bool do_blocked; 55 1.1 mrg index_type r_ex, a_ex; 56 1.1 mrg 57 1.1 mrg which = which - 1; 58 1.1 mrg sstride[0] = 0; 59 1.1 mrg rstride[0] = 0; 60 1.1 mrg 61 1.1 mrg extent[0] = 1; 62 1.1 mrg count[0] = 0; 63 1.1 mrg n = 0; 64 1.1 mrg /* Initialized for avoiding compiler warnings. */ 65 1.1 mrg roffset = 1; 66 1.1 mrg soffset = 1; 67 1.1 mrg len = 0; 68 1.1 mrg 69 1.1 mrg r_ex = 1; 70 1.1 mrg a_ex = 1; 71 1.1 mrg 72 1.1 mrg if (which > 0) 73 1.1 mrg { 74 1.1 mrg /* Test if both ret and array are contiguous. */ 75 1.1 mrg do_blocked = true; 76 1.1 mrg dim = GFC_DESCRIPTOR_RANK (array); 77 1.1 mrg for (n = 0; n < dim; n ++) 78 1.1 mrg { 79 1.1 mrg index_type rs, as; 80 1.1 mrg rs = GFC_DESCRIPTOR_STRIDE (ret, n); 81 1.1 mrg if (rs != r_ex) 82 1.1 mrg { 83 1.1 mrg do_blocked = false; 84 1.1 mrg break; 85 1.1 mrg } 86 1.1 mrg as = GFC_DESCRIPTOR_STRIDE (array, n); 87 1.1 mrg if (as != a_ex) 88 1.1 mrg { 89 1.1 mrg do_blocked = false; 90 1.1 mrg break; 91 1.1 mrg } 92 1.1 mrg r_ex *= GFC_DESCRIPTOR_EXTENT (ret, n); 93 1.1 mrg a_ex *= GFC_DESCRIPTOR_EXTENT (array, n); 94 1.1 mrg } 95 1.1 mrg } 96 1.1 mrg else 97 1.1 mrg do_blocked = false; 98 1.1 mrg 99 1.1 mrg n = 0; 100 1.1 mrg 101 1.1 mrg if (do_blocked) 102 1.1 mrg { 103 1.1 mrg /* For contiguous arrays, use the relationship that 104 1.1 mrg 105 1.1 mrg dimension(n1,n2,n3) :: a, b 106 1.1 mrg b = cshift(a,sh,3) 107 1.1 mrg 108 1.1 mrg can be dealt with as if 109 1.1 mrg 110 1.1 mrg dimension(n1*n2*n3) :: an, bn 111 1.1 mrg bn = cshift(a,sh*n1*n2,1) 112 1.1 mrg 113 1.1 mrg we can used a more blocked algorithm for dim>1. */ 114 1.1 mrg sstride[0] = 1; 115 1.1 mrg rstride[0] = 1; 116 1.1 mrg roffset = 1; 117 1.1 mrg soffset = 1; 118 1.1 mrg len = GFC_DESCRIPTOR_STRIDE(array, which) 119 1.1 mrg * GFC_DESCRIPTOR_EXTENT(array, which); 120 1.1 mrg shift *= GFC_DESCRIPTOR_STRIDE(array, which); 121 1.1 mrg for (dim = which + 1; dim < GFC_DESCRIPTOR_RANK (array); dim++) 122 1.1 mrg { 123 1.1 mrg count[n] = 0; 124 1.1 mrg extent[n] = GFC_DESCRIPTOR_EXTENT(array,dim); 125 1.1 mrg rstride[n] = GFC_DESCRIPTOR_STRIDE(ret,dim); 126 1.1 mrg sstride[n] = GFC_DESCRIPTOR_STRIDE(array,dim); 127 1.1 mrg n++; 128 1.1 mrg } 129 1.1 mrg dim = GFC_DESCRIPTOR_RANK (array) - which; 130 1.1 mrg } 131 1.1 mrg else 132 1.1 mrg { 133 1.1 mrg for (dim = 0; dim < GFC_DESCRIPTOR_RANK (array); dim++) 134 1.1 mrg { 135 1.1 mrg if (dim == which) 136 1.1 mrg { 137 1.1 mrg roffset = GFC_DESCRIPTOR_STRIDE(ret,dim); 138 1.1 mrg if (roffset == 0) 139 1.1 mrg roffset = 1; 140 1.1 mrg soffset = GFC_DESCRIPTOR_STRIDE(array,dim); 141 1.1 mrg if (soffset == 0) 142 1.1 mrg soffset = 1; 143 1.1 mrg len = GFC_DESCRIPTOR_EXTENT(array,dim); 144 1.1 mrg } 145 1.1 mrg else 146 1.1 mrg { 147 1.1 mrg count[n] = 0; 148 1.1 mrg extent[n] = GFC_DESCRIPTOR_EXTENT(array,dim); 149 1.1 mrg rstride[n] = GFC_DESCRIPTOR_STRIDE(ret,dim); 150 1.1 mrg sstride[n] = GFC_DESCRIPTOR_STRIDE(array,dim); 151 1.1 mrg n++; 152 1.1 mrg } 153 1.1 mrg } 154 1.1 mrg if (sstride[0] == 0) 155 1.1 mrg sstride[0] = 1; 156 1.1 mrg if (rstride[0] == 0) 157 1.1 mrg rstride[0] = 1; 158 1.1 mrg 159 1.1 mrg dim = GFC_DESCRIPTOR_RANK (array); 160 1.1 mrg } 161 1.1 mrg 162 1.1 mrg rstride0 = rstride[0]; 163 1.1 mrg sstride0 = sstride[0]; 164 1.1 mrg rptr = ret->base_addr; 165 1.1 mrg sptr = array->base_addr; 166 1.1 mrg 167 1.1 mrg /* Avoid the costly modulo for trivially in-bound shifts. */ 168 1.1 mrg if (shift < 0 || shift >= len) 169 1.1 mrg { 170 1.1 mrg shift = len == 0 ? 0 : shift % (ptrdiff_t)len; 171 1.1 mrg if (shift < 0) 172 1.1 mrg shift += len; 173 1.1 mrg } 174 1.1 mrg 175 1.1 mrg while (rptr) 176 1.1 mrg { 177 1.1 mrg /* Do the shift for this dimension. */ 178 1.1 mrg 179 1.1 mrg /* If elements are contiguous, perform the operation 180 1.1 mrg in two block moves. */ 181 1.1 mrg if (soffset == 1 && roffset == 1) 182 1.1 mrg { 183 1.1 mrg size_t len1 = shift * sizeof (GFC_COMPLEX_10); 184 1.1 mrg size_t len2 = (len - shift) * sizeof (GFC_COMPLEX_10); 185 1.1 mrg memcpy (rptr, sptr + shift, len2); 186 1.1 mrg memcpy (rptr + (len - shift), sptr, len1); 187 1.1 mrg } 188 1.1 mrg else 189 1.1 mrg { 190 1.1 mrg /* Otherwise, we will have to perform the copy one element at 191 1.1 mrg a time. */ 192 1.1 mrg GFC_COMPLEX_10 *dest = rptr; 193 1.1 mrg const GFC_COMPLEX_10 *src = &sptr[shift * soffset]; 194 1.1 mrg 195 1.1 mrg for (n = 0; n < len - shift; n++) 196 1.1 mrg { 197 1.1 mrg *dest = *src; 198 1.1 mrg dest += roffset; 199 1.1 mrg src += soffset; 200 1.1 mrg } 201 1.1 mrg for (src = sptr, n = 0; n < shift; n++) 202 1.1 mrg { 203 1.1 mrg *dest = *src; 204 1.1 mrg dest += roffset; 205 1.1 mrg src += soffset; 206 1.1 mrg } 207 1.1 mrg } 208 1.1 mrg 209 1.1 mrg /* Advance to the next section. */ 210 1.1 mrg rptr += rstride0; 211 1.1 mrg sptr += sstride0; 212 1.1 mrg count[0]++; 213 1.1 mrg n = 0; 214 1.1 mrg while (count[n] == extent[n]) 215 1.1 mrg { 216 1.1 mrg /* When we get to the end of a dimension, reset it and increment 217 1.1 mrg the next dimension. */ 218 1.1 mrg count[n] = 0; 219 1.1 mrg /* We could precalculate these products, but this is a less 220 1.1 mrg frequently used path so probably not worth it. */ 221 1.1 mrg rptr -= rstride[n] * extent[n]; 222 1.1 mrg sptr -= sstride[n] * extent[n]; 223 1.1 mrg n++; 224 1.1 mrg if (n >= dim - 1) 225 1.1 mrg { 226 1.1 mrg /* Break out of the loop. */ 227 1.1 mrg rptr = NULL; 228 1.1 mrg break; 229 1.1 mrg } 230 1.1 mrg else 231 1.1 mrg { 232 1.1 mrg count[n]++; 233 1.1 mrg rptr += rstride[n]; 234 1.1 mrg sptr += sstride[n]; 235 1.1 mrg } 236 1.1 mrg } 237 1.1 mrg } 238 1.1 mrg 239 1.1 mrg return; 240 1.1 mrg } 241 1.1 mrg 242 1.1 mrg #endif 243