1 1.1 mrg `/* Special implementation of the SPREAD intrinsic 2 1.1.1.3 mrg Copyright (C) 2008-2022 Free Software Foundation, Inc. 3 1.1 mrg Contributed by Thomas Koenig <tkoenig (a] gcc.gnu.org>, based on 4 1.1 mrg spread_generic.c written by Paul Brook <paul (a] nowt.org> 5 1.1 mrg 6 1.1 mrg This file is part of the GNU Fortran runtime library (libgfortran). 7 1.1 mrg 8 1.1 mrg Libgfortran is free software; you can redistribute it and/or 9 1.1 mrg modify it under the terms of the GNU General Public 10 1.1 mrg License as published by the Free Software Foundation; either 11 1.1 mrg version 3 of the License, or (at your option) any later version. 12 1.1 mrg 13 1.1 mrg Ligbfortran is distributed in the hope that it will be useful, 14 1.1 mrg but WITHOUT ANY WARRANTY; without even the implied warranty of 15 1.1 mrg MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 1.1 mrg GNU General Public License for more details. 17 1.1 mrg 18 1.1 mrg Under Section 7 of GPL version 3, you are granted additional 19 1.1 mrg permissions described in the GCC Runtime Library Exception, version 20 1.1 mrg 3.1, as published by the Free Software Foundation. 21 1.1 mrg 22 1.1 mrg You should have received a copy of the GNU General Public License and 23 1.1 mrg a copy of the GCC Runtime Library Exception along with this program; 24 1.1 mrg see the files COPYING3 and COPYING.RUNTIME respectively. If not, see 25 1.1 mrg <http://www.gnu.org/licenses/>. */ 26 1.1 mrg 27 1.1 mrg #include "libgfortran.h" 28 1.1 mrg #include <string.h>' 29 1.1 mrg 30 1.1 mrg include(iparm.m4)dnl 31 1.1 mrg 32 1.1 mrg `#if defined (HAVE_'rtype_name`) 33 1.1 mrg 34 1.1 mrg void 35 1.1 mrg spread_'rtype_code` ('rtype` *ret, const 'rtype` *source, 36 1.1 mrg const index_type along, const index_type pncopies) 37 1.1 mrg { 38 1.1 mrg /* r.* indicates the return array. */ 39 1.1 mrg index_type rstride[GFC_MAX_DIMENSIONS]; 40 1.1 mrg index_type rstride0; 41 1.1 mrg index_type rdelta = 0; 42 1.1 mrg index_type rrank; 43 1.1 mrg index_type rs; 44 1.1 mrg 'rtype_name` *rptr; 45 1.1 mrg 'rtype_name` * restrict dest; 46 1.1 mrg /* s.* indicates the source array. */ 47 1.1 mrg index_type sstride[GFC_MAX_DIMENSIONS]; 48 1.1 mrg index_type sstride0; 49 1.1 mrg index_type srank; 50 1.1 mrg const 'rtype_name` *sptr; 51 1.1 mrg 52 1.1 mrg index_type count[GFC_MAX_DIMENSIONS]; 53 1.1 mrg index_type extent[GFC_MAX_DIMENSIONS]; 54 1.1 mrg index_type n; 55 1.1 mrg index_type dim; 56 1.1 mrg index_type ncopies; 57 1.1 mrg 58 1.1 mrg srank = GFC_DESCRIPTOR_RANK(source); 59 1.1 mrg 60 1.1 mrg rrank = srank + 1; 61 1.1 mrg if (rrank > GFC_MAX_DIMENSIONS) 62 1.1 mrg runtime_error ("return rank too large in spread()"); 63 1.1 mrg 64 1.1 mrg if (along > rrank) 65 1.1 mrg runtime_error ("dim outside of rank in spread()"); 66 1.1 mrg 67 1.1 mrg ncopies = pncopies; 68 1.1 mrg 69 1.1 mrg if (ret->base_addr == NULL) 70 1.1 mrg { 71 1.1 mrg 72 1.1 mrg size_t ub, stride; 73 1.1 mrg 74 1.1 mrg /* The front end has signalled that we need to populate the 75 1.1 mrg return array descriptor. */ 76 1.1 mrg ret->dtype.rank = rrank; 77 1.1 mrg 78 1.1 mrg dim = 0; 79 1.1 mrg rs = 1; 80 1.1 mrg for (n = 0; n < rrank; n++) 81 1.1 mrg { 82 1.1 mrg stride = rs; 83 1.1 mrg if (n == along - 1) 84 1.1 mrg { 85 1.1 mrg ub = ncopies - 1; 86 1.1 mrg rdelta = rs; 87 1.1 mrg rs *= ncopies; 88 1.1 mrg } 89 1.1 mrg else 90 1.1 mrg { 91 1.1 mrg count[dim] = 0; 92 1.1 mrg extent[dim] = GFC_DESCRIPTOR_EXTENT(source,dim); 93 1.1 mrg sstride[dim] = GFC_DESCRIPTOR_STRIDE(source,dim); 94 1.1 mrg rstride[dim] = rs; 95 1.1 mrg 96 1.1 mrg ub = extent[dim] - 1; 97 1.1 mrg rs *= extent[dim]; 98 1.1 mrg dim++; 99 1.1 mrg } 100 1.1 mrg GFC_DIMENSION_SET(ret->dim[n], 0, ub, stride); 101 1.1 mrg } 102 1.1 mrg ret->offset = 0; 103 1.1 mrg 104 1.1 mrg /* xmallocarray allocates a single byte for zero size. */ 105 1.1 mrg ret->base_addr = xmallocarray (rs, sizeof('rtype_name`)); 106 1.1 mrg if (rs <= 0) 107 1.1 mrg return; 108 1.1 mrg } 109 1.1 mrg else 110 1.1 mrg { 111 1.1 mrg int zero_sized; 112 1.1 mrg 113 1.1 mrg zero_sized = 0; 114 1.1 mrg 115 1.1 mrg dim = 0; 116 1.1 mrg if (GFC_DESCRIPTOR_RANK(ret) != rrank) 117 1.1 mrg runtime_error ("rank mismatch in spread()"); 118 1.1 mrg 119 1.1 mrg if (unlikely (compile_options.bounds_check)) 120 1.1 mrg { 121 1.1 mrg for (n = 0; n < rrank; n++) 122 1.1 mrg { 123 1.1 mrg index_type ret_extent; 124 1.1 mrg 125 1.1 mrg ret_extent = GFC_DESCRIPTOR_EXTENT(ret,n); 126 1.1 mrg if (n == along - 1) 127 1.1 mrg { 128 1.1 mrg rdelta = GFC_DESCRIPTOR_STRIDE(ret,n); 129 1.1 mrg 130 1.1 mrg if (ret_extent != ncopies) 131 1.1 mrg runtime_error("Incorrect extent in return value of SPREAD" 132 1.1 mrg " intrinsic in dimension %ld: is %ld," 133 1.1 mrg " should be %ld", (long int) n+1, 134 1.1 mrg (long int) ret_extent, (long int) ncopies); 135 1.1 mrg } 136 1.1 mrg else 137 1.1 mrg { 138 1.1 mrg count[dim] = 0; 139 1.1 mrg extent[dim] = GFC_DESCRIPTOR_EXTENT(source,dim); 140 1.1 mrg if (ret_extent != extent[dim]) 141 1.1 mrg runtime_error("Incorrect extent in return value of SPREAD" 142 1.1 mrg " intrinsic in dimension %ld: is %ld," 143 1.1 mrg " should be %ld", (long int) n+1, 144 1.1 mrg (long int) ret_extent, 145 1.1 mrg (long int) extent[dim]); 146 1.1 mrg 147 1.1 mrg if (extent[dim] <= 0) 148 1.1 mrg zero_sized = 1; 149 1.1 mrg sstride[dim] = GFC_DESCRIPTOR_STRIDE(source,dim); 150 1.1 mrg rstride[dim] = GFC_DESCRIPTOR_STRIDE(ret,n); 151 1.1 mrg dim++; 152 1.1 mrg } 153 1.1 mrg } 154 1.1 mrg } 155 1.1 mrg else 156 1.1 mrg { 157 1.1 mrg for (n = 0; n < rrank; n++) 158 1.1 mrg { 159 1.1 mrg if (n == along - 1) 160 1.1 mrg { 161 1.1 mrg rdelta = GFC_DESCRIPTOR_STRIDE(ret,n); 162 1.1 mrg } 163 1.1 mrg else 164 1.1 mrg { 165 1.1 mrg count[dim] = 0; 166 1.1 mrg extent[dim] = GFC_DESCRIPTOR_EXTENT(source,dim); 167 1.1 mrg if (extent[dim] <= 0) 168 1.1 mrg zero_sized = 1; 169 1.1 mrg sstride[dim] = GFC_DESCRIPTOR_STRIDE(source,dim); 170 1.1 mrg rstride[dim] = GFC_DESCRIPTOR_STRIDE(ret,n); 171 1.1 mrg dim++; 172 1.1 mrg } 173 1.1 mrg } 174 1.1 mrg } 175 1.1 mrg 176 1.1 mrg if (zero_sized) 177 1.1 mrg return; 178 1.1 mrg 179 1.1 mrg if (sstride[0] == 0) 180 1.1 mrg sstride[0] = 1; 181 1.1 mrg } 182 1.1 mrg sstride0 = sstride[0]; 183 1.1 mrg rstride0 = rstride[0]; 184 1.1 mrg rptr = ret->base_addr; 185 1.1 mrg sptr = source->base_addr; 186 1.1 mrg 187 1.1 mrg while (sptr) 188 1.1 mrg { 189 1.1 mrg /* Spread this element. */ 190 1.1 mrg dest = rptr; 191 1.1 mrg for (n = 0; n < ncopies; n++) 192 1.1 mrg { 193 1.1 mrg *dest = *sptr; 194 1.1 mrg dest += rdelta; 195 1.1 mrg } 196 1.1 mrg /* Advance to the next element. */ 197 1.1 mrg sptr += sstride0; 198 1.1 mrg rptr += rstride0; 199 1.1 mrg count[0]++; 200 1.1 mrg n = 0; 201 1.1 mrg while (count[n] == extent[n]) 202 1.1 mrg { 203 1.1 mrg /* When we get to the end of a dimension, reset it and increment 204 1.1 mrg the next dimension. */ 205 1.1 mrg count[n] = 0; 206 1.1 mrg /* We could precalculate these products, but this is a less 207 1.1 mrg frequently used path so probably not worth it. */ 208 1.1 mrg sptr -= sstride[n] * extent[n]; 209 1.1 mrg rptr -= rstride[n] * extent[n]; 210 1.1 mrg n++; 211 1.1 mrg if (n >= srank) 212 1.1 mrg { 213 1.1 mrg /* Break out of the loop. */ 214 1.1 mrg sptr = NULL; 215 1.1 mrg break; 216 1.1 mrg } 217 1.1 mrg else 218 1.1 mrg { 219 1.1 mrg count[n]++; 220 1.1 mrg sptr += sstride[n]; 221 1.1 mrg rptr += rstride[n]; 222 1.1 mrg } 223 1.1 mrg } 224 1.1 mrg } 225 1.1 mrg } 226 1.1 mrg 227 1.1 mrg /* This version of spread_internal treats the special case of a scalar 228 1.1 mrg source. This is much simpler than the more general case above. */ 229 1.1 mrg 230 1.1 mrg void 231 1.1 mrg spread_scalar_'rtype_code` ('rtype` *ret, const 'rtype_name` *source, 232 1.1 mrg const index_type along, const index_type ncopies) 233 1.1 mrg { 234 1.1 mrg 'rtype_name` * restrict dest; 235 1.1 mrg index_type stride; 236 1.1 mrg 237 1.1 mrg if (GFC_DESCRIPTOR_RANK (ret) != 1) 238 1.1 mrg runtime_error ("incorrect destination rank in spread()"); 239 1.1 mrg 240 1.1 mrg if (along > 1) 241 1.1 mrg runtime_error ("dim outside of rank in spread()"); 242 1.1 mrg 243 1.1 mrg if (ret->base_addr == NULL) 244 1.1 mrg { 245 1.1 mrg ret->base_addr = xmallocarray (ncopies, sizeof ('rtype_name`)); 246 1.1 mrg ret->offset = 0; 247 1.1 mrg GFC_DIMENSION_SET(ret->dim[0], 0, ncopies - 1, 1); 248 1.1 mrg } 249 1.1 mrg else 250 1.1 mrg { 251 1.1 mrg if (ncopies - 1 > (GFC_DESCRIPTOR_EXTENT(ret,0) - 1) 252 1.1 mrg / GFC_DESCRIPTOR_STRIDE(ret,0)) 253 1.1 mrg runtime_error ("dim too large in spread()"); 254 1.1 mrg } 255 1.1 mrg 256 1.1 mrg dest = ret->base_addr; 257 1.1 mrg stride = GFC_DESCRIPTOR_STRIDE(ret,0); 258 1.1 mrg 259 1.1 mrg for (index_type n = 0; n < ncopies; n++) 260 1.1 mrg { 261 1.1 mrg *dest = *source; 262 1.1 mrg dest += stride; 263 1.1 mrg } 264 1.1 mrg } 265 1.1 mrg 266 1.1 mrg #endif 267 1.1 mrg ' 268