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