1627f7eb2Smrg`/* Implementation of the RESHAPE intrinsic 2*4c3eb207Smrg Copyright (C) 2002-2020 Free Software Foundation, Inc. 3627f7eb2Smrg Contributed by Paul Brook <paul@nowt.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 28627f7eb2Smrginclude(iparm.m4)dnl 29627f7eb2Smrg 30627f7eb2Smrg`#if defined (HAVE_'rtype_name`) 31627f7eb2Smrg 32627f7eb2Smrgtypedef GFC_FULL_ARRAY_DESCRIPTOR(1, 'index_type`) 'shape_type`;' 33627f7eb2Smrg 34627f7eb2Smrgdnl For integer routines, only the kind (ie size) is used to name the 35627f7eb2Smrgdnl function. The same function will be used for integer and logical 36627f7eb2Smrgdnl arrays of the same kind. 37627f7eb2Smrg 38627f7eb2Smrg`extern void reshape_'rtype_ccode` ('rtype` * const restrict, 39627f7eb2Smrg 'rtype` * const restrict, 40627f7eb2Smrg 'shape_type` * const restrict, 41627f7eb2Smrg 'rtype` * const restrict, 42627f7eb2Smrg 'shape_type` * const restrict); 43627f7eb2Smrgexport_proto(reshape_'rtype_ccode`); 44627f7eb2Smrg 45627f7eb2Smrgvoid 46627f7eb2Smrgreshape_'rtype_ccode` ('rtype` * const restrict ret, 47627f7eb2Smrg 'rtype` * const restrict source, 48627f7eb2Smrg 'shape_type` * const restrict shape, 49627f7eb2Smrg 'rtype` * const restrict pad, 50627f7eb2Smrg 'shape_type` * const restrict order) 51627f7eb2Smrg{ 52627f7eb2Smrg /* r.* indicates the return array. */ 53627f7eb2Smrg index_type rcount[GFC_MAX_DIMENSIONS]; 54627f7eb2Smrg index_type rextent[GFC_MAX_DIMENSIONS]; 55627f7eb2Smrg index_type rstride[GFC_MAX_DIMENSIONS]; 56627f7eb2Smrg index_type rstride0; 57627f7eb2Smrg index_type rdim; 58627f7eb2Smrg index_type rsize; 59627f7eb2Smrg index_type rs; 60627f7eb2Smrg index_type rex; 61627f7eb2Smrg 'rtype_name` *rptr; 62627f7eb2Smrg /* s.* indicates the source array. */ 63627f7eb2Smrg index_type scount[GFC_MAX_DIMENSIONS]; 64627f7eb2Smrg index_type sextent[GFC_MAX_DIMENSIONS]; 65627f7eb2Smrg index_type sstride[GFC_MAX_DIMENSIONS]; 66627f7eb2Smrg index_type sstride0; 67627f7eb2Smrg index_type sdim; 68627f7eb2Smrg index_type ssize; 69627f7eb2Smrg const 'rtype_name` *sptr; 70627f7eb2Smrg /* p.* indicates the pad array. */ 71627f7eb2Smrg index_type pcount[GFC_MAX_DIMENSIONS]; 72627f7eb2Smrg index_type pextent[GFC_MAX_DIMENSIONS]; 73627f7eb2Smrg index_type pstride[GFC_MAX_DIMENSIONS]; 74627f7eb2Smrg index_type pdim; 75627f7eb2Smrg index_type psize; 76627f7eb2Smrg const 'rtype_name` *pptr; 77627f7eb2Smrg 78627f7eb2Smrg const 'rtype_name` *src; 79627f7eb2Smrg int sempty, pempty, shape_empty; 80627f7eb2Smrg index_type shape_data[GFC_MAX_DIMENSIONS]; 81627f7eb2Smrg 82627f7eb2Smrg rdim = GFC_DESCRIPTOR_EXTENT(shape,0); 83627f7eb2Smrg /* rdim is always > 0; this lets the compiler optimize more and 84627f7eb2Smrg avoids a potential warning. */ 85627f7eb2Smrg GFC_ASSERT(rdim>0); 86627f7eb2Smrg 87627f7eb2Smrg if (rdim != GFC_DESCRIPTOR_RANK(ret)) 88627f7eb2Smrg runtime_error("rank of return array incorrect in RESHAPE intrinsic"); 89627f7eb2Smrg 90627f7eb2Smrg shape_empty = 0; 91627f7eb2Smrg 92627f7eb2Smrg for (index_type n = 0; n < rdim; n++) 93627f7eb2Smrg { 94627f7eb2Smrg shape_data[n] = shape->base_addr[n * GFC_DESCRIPTOR_STRIDE(shape,0)]; 95627f7eb2Smrg if (shape_data[n] <= 0) 96627f7eb2Smrg { 97627f7eb2Smrg shape_data[n] = 0; 98627f7eb2Smrg shape_empty = 1; 99627f7eb2Smrg } 100627f7eb2Smrg } 101627f7eb2Smrg 102627f7eb2Smrg if (ret->base_addr == NULL) 103627f7eb2Smrg { 104627f7eb2Smrg index_type alloc_size; 105627f7eb2Smrg 106627f7eb2Smrg rs = 1; 107627f7eb2Smrg for (index_type n = 0; n < rdim; n++) 108627f7eb2Smrg { 109627f7eb2Smrg rex = shape_data[n]; 110627f7eb2Smrg 111627f7eb2Smrg GFC_DIMENSION_SET(ret->dim[n], 0, rex - 1, rs); 112627f7eb2Smrg 113627f7eb2Smrg rs *= rex; 114627f7eb2Smrg } 115627f7eb2Smrg ret->offset = 0; 116627f7eb2Smrg 117627f7eb2Smrg if (unlikely (rs < 1)) 118627f7eb2Smrg alloc_size = 0; 119627f7eb2Smrg else 120627f7eb2Smrg alloc_size = rs; 121627f7eb2Smrg 122627f7eb2Smrg ret->base_addr = xmallocarray (alloc_size, sizeof ('rtype_name`)); 123627f7eb2Smrg ret->dtype.rank = rdim; 124627f7eb2Smrg } 125627f7eb2Smrg 126627f7eb2Smrg if (shape_empty) 127627f7eb2Smrg return; 128627f7eb2Smrg 129627f7eb2Smrg if (pad) 130627f7eb2Smrg { 131627f7eb2Smrg pdim = GFC_DESCRIPTOR_RANK (pad); 132627f7eb2Smrg psize = 1; 133627f7eb2Smrg pempty = 0; 134627f7eb2Smrg for (index_type n = 0; n < pdim; n++) 135627f7eb2Smrg { 136627f7eb2Smrg pcount[n] = 0; 137627f7eb2Smrg pstride[n] = GFC_DESCRIPTOR_STRIDE(pad,n); 138627f7eb2Smrg pextent[n] = GFC_DESCRIPTOR_EXTENT(pad,n); 139627f7eb2Smrg if (pextent[n] <= 0) 140627f7eb2Smrg { 141627f7eb2Smrg pempty = 1; 142627f7eb2Smrg pextent[n] = 0; 143627f7eb2Smrg } 144627f7eb2Smrg 145627f7eb2Smrg if (psize == pstride[n]) 146627f7eb2Smrg psize *= pextent[n]; 147627f7eb2Smrg else 148627f7eb2Smrg psize = 0; 149627f7eb2Smrg } 150627f7eb2Smrg pptr = pad->base_addr; 151627f7eb2Smrg } 152627f7eb2Smrg else 153627f7eb2Smrg { 154627f7eb2Smrg pdim = 0; 155627f7eb2Smrg psize = 1; 156627f7eb2Smrg pempty = 1; 157627f7eb2Smrg pptr = NULL; 158627f7eb2Smrg } 159627f7eb2Smrg 160627f7eb2Smrg if (unlikely (compile_options.bounds_check)) 161627f7eb2Smrg { 162627f7eb2Smrg index_type ret_extent, source_extent; 163627f7eb2Smrg 164627f7eb2Smrg rs = 1; 165627f7eb2Smrg for (index_type n = 0; n < rdim; n++) 166627f7eb2Smrg { 167627f7eb2Smrg rs *= shape_data[n]; 168627f7eb2Smrg ret_extent = GFC_DESCRIPTOR_EXTENT(ret,n); 169627f7eb2Smrg if (ret_extent != shape_data[n]) 170627f7eb2Smrg runtime_error("Incorrect extent in return value of RESHAPE" 171627f7eb2Smrg " intrinsic in dimension %ld: is %ld," 172627f7eb2Smrg " should be %ld", (long int) n+1, 173627f7eb2Smrg (long int) ret_extent, (long int) shape_data[n]); 174627f7eb2Smrg } 175627f7eb2Smrg 176627f7eb2Smrg source_extent = 1; 177627f7eb2Smrg sdim = GFC_DESCRIPTOR_RANK (source); 178627f7eb2Smrg for (index_type n = 0; n < sdim; n++) 179627f7eb2Smrg { 180627f7eb2Smrg index_type se; 181627f7eb2Smrg se = GFC_DESCRIPTOR_EXTENT(source,n); 182627f7eb2Smrg source_extent *= se > 0 ? se : 0; 183627f7eb2Smrg } 184627f7eb2Smrg 185627f7eb2Smrg if (rs > source_extent && (!pad || pempty)) 186627f7eb2Smrg runtime_error("Incorrect size in SOURCE argument to RESHAPE" 187627f7eb2Smrg " intrinsic: is %ld, should be %ld", 188627f7eb2Smrg (long int) source_extent, (long int) rs); 189627f7eb2Smrg 190627f7eb2Smrg if (order) 191627f7eb2Smrg { 192627f7eb2Smrg int seen[GFC_MAX_DIMENSIONS]; 193627f7eb2Smrg index_type v; 194627f7eb2Smrg 195627f7eb2Smrg for (index_type n = 0; n < rdim; n++) 196627f7eb2Smrg seen[n] = 0; 197627f7eb2Smrg 198627f7eb2Smrg for (index_type n = 0; n < rdim; n++) 199627f7eb2Smrg { 200627f7eb2Smrg v = order->base_addr[n * GFC_DESCRIPTOR_STRIDE(order,0)] - 1; 201627f7eb2Smrg 202627f7eb2Smrg if (v < 0 || v >= rdim) 203627f7eb2Smrg runtime_error("Value %ld out of range in ORDER argument" 204627f7eb2Smrg " to RESHAPE intrinsic", (long int) v + 1); 205627f7eb2Smrg 206627f7eb2Smrg if (seen[v] != 0) 207627f7eb2Smrg runtime_error("Duplicate value %ld in ORDER argument to" 208627f7eb2Smrg " RESHAPE intrinsic", (long int) v + 1); 209627f7eb2Smrg 210627f7eb2Smrg seen[v] = 1; 211627f7eb2Smrg } 212627f7eb2Smrg } 213627f7eb2Smrg } 214627f7eb2Smrg 215627f7eb2Smrg rsize = 1; 216627f7eb2Smrg for (index_type n = 0; n < rdim; n++) 217627f7eb2Smrg { 218627f7eb2Smrg index_type dim; 219627f7eb2Smrg if (order) 220627f7eb2Smrg dim = order->base_addr[n * GFC_DESCRIPTOR_STRIDE(order,0)] - 1; 221627f7eb2Smrg else 222627f7eb2Smrg dim = n; 223627f7eb2Smrg 224627f7eb2Smrg rcount[n] = 0; 225627f7eb2Smrg rstride[n] = GFC_DESCRIPTOR_STRIDE(ret,dim); 226627f7eb2Smrg rextent[n] = GFC_DESCRIPTOR_EXTENT(ret,dim); 227627f7eb2Smrg if (rextent[n] < 0) 228627f7eb2Smrg rextent[n] = 0; 229627f7eb2Smrg 230627f7eb2Smrg if (rextent[n] != shape_data[dim]) 231627f7eb2Smrg runtime_error ("shape and target do not conform"); 232627f7eb2Smrg 233627f7eb2Smrg if (rsize == rstride[n]) 234627f7eb2Smrg rsize *= rextent[n]; 235627f7eb2Smrg else 236627f7eb2Smrg rsize = 0; 237627f7eb2Smrg if (rextent[n] <= 0) 238627f7eb2Smrg return; 239627f7eb2Smrg } 240627f7eb2Smrg 241627f7eb2Smrg sdim = GFC_DESCRIPTOR_RANK (source); 242627f7eb2Smrg 243627f7eb2Smrg /* sdim is always > 0; this lets the compiler optimize more and 244627f7eb2Smrg avoids a warning. */ 245627f7eb2Smrg GFC_ASSERT(sdim>0); 246627f7eb2Smrg 247627f7eb2Smrg ssize = 1; 248627f7eb2Smrg sempty = 0; 249627f7eb2Smrg for (index_type n = 0; n < sdim; n++) 250627f7eb2Smrg { 251627f7eb2Smrg scount[n] = 0; 252627f7eb2Smrg sstride[n] = GFC_DESCRIPTOR_STRIDE(source,n); 253627f7eb2Smrg sextent[n] = GFC_DESCRIPTOR_EXTENT(source,n); 254627f7eb2Smrg if (sextent[n] <= 0) 255627f7eb2Smrg { 256627f7eb2Smrg sempty = 1; 257627f7eb2Smrg sextent[n] = 0; 258627f7eb2Smrg } 259627f7eb2Smrg 260627f7eb2Smrg if (ssize == sstride[n]) 261627f7eb2Smrg ssize *= sextent[n]; 262627f7eb2Smrg else 263627f7eb2Smrg ssize = 0; 264627f7eb2Smrg } 265627f7eb2Smrg 266627f7eb2Smrg if (rsize != 0 && ssize != 0 && psize != 0) 267627f7eb2Smrg { 268627f7eb2Smrg rsize *= sizeof ('rtype_name`); 269627f7eb2Smrg ssize *= sizeof ('rtype_name`); 270627f7eb2Smrg psize *= sizeof ('rtype_name`); 271627f7eb2Smrg reshape_packed ((char *)ret->base_addr, rsize, (char *)source->base_addr, 272627f7eb2Smrg ssize, pad ? (char *)pad->base_addr : NULL, psize); 273627f7eb2Smrg return; 274627f7eb2Smrg } 275627f7eb2Smrg rptr = ret->base_addr; 276627f7eb2Smrg src = sptr = source->base_addr; 277627f7eb2Smrg rstride0 = rstride[0]; 278627f7eb2Smrg sstride0 = sstride[0]; 279627f7eb2Smrg 280627f7eb2Smrg if (sempty && pempty) 281627f7eb2Smrg abort (); 282627f7eb2Smrg 283627f7eb2Smrg if (sempty) 284627f7eb2Smrg { 285627f7eb2Smrg /* Pretend we are using the pad array the first time around, too. */ 286627f7eb2Smrg src = pptr; 287627f7eb2Smrg sptr = pptr; 288627f7eb2Smrg sdim = pdim; 289627f7eb2Smrg for (index_type dim = 0; dim < pdim; dim++) 290627f7eb2Smrg { 291627f7eb2Smrg scount[dim] = pcount[dim]; 292627f7eb2Smrg sextent[dim] = pextent[dim]; 293627f7eb2Smrg sstride[dim] = pstride[dim]; 294627f7eb2Smrg sstride0 = pstride[0]; 295627f7eb2Smrg } 296627f7eb2Smrg } 297627f7eb2Smrg 298627f7eb2Smrg while (rptr) 299627f7eb2Smrg { 300627f7eb2Smrg /* Select between the source and pad arrays. */ 301627f7eb2Smrg *rptr = *src; 302627f7eb2Smrg /* Advance to the next element. */ 303627f7eb2Smrg rptr += rstride0; 304627f7eb2Smrg src += sstride0; 305627f7eb2Smrg rcount[0]++; 306627f7eb2Smrg scount[0]++; 307627f7eb2Smrg 308627f7eb2Smrg /* Advance to the next destination element. */ 309627f7eb2Smrg index_type n = 0; 310627f7eb2Smrg while (rcount[n] == rextent[n]) 311627f7eb2Smrg { 312627f7eb2Smrg /* When we get to the end of a dimension, reset it and increment 313627f7eb2Smrg the next dimension. */ 314627f7eb2Smrg rcount[n] = 0; 315627f7eb2Smrg /* We could precalculate these products, but this is a less 316627f7eb2Smrg frequently used path so probably not worth it. */ 317627f7eb2Smrg rptr -= rstride[n] * rextent[n]; 318627f7eb2Smrg n++; 319627f7eb2Smrg if (n == rdim) 320627f7eb2Smrg { 321627f7eb2Smrg /* Break out of the loop. */ 322627f7eb2Smrg rptr = NULL; 323627f7eb2Smrg break; 324627f7eb2Smrg } 325627f7eb2Smrg else 326627f7eb2Smrg { 327627f7eb2Smrg rcount[n]++; 328627f7eb2Smrg rptr += rstride[n]; 329627f7eb2Smrg } 330627f7eb2Smrg } 331627f7eb2Smrg /* Advance to the next source element. */ 332627f7eb2Smrg n = 0; 333627f7eb2Smrg while (scount[n] == sextent[n]) 334627f7eb2Smrg { 335627f7eb2Smrg /* When we get to the end of a dimension, reset it and increment 336627f7eb2Smrg the next dimension. */ 337627f7eb2Smrg scount[n] = 0; 338627f7eb2Smrg /* We could precalculate these products, but this is a less 339627f7eb2Smrg frequently used path so probably not worth it. */ 340627f7eb2Smrg src -= sstride[n] * sextent[n]; 341627f7eb2Smrg n++; 342627f7eb2Smrg if (n == sdim) 343627f7eb2Smrg { 344627f7eb2Smrg if (sptr && pad) 345627f7eb2Smrg { 346627f7eb2Smrg /* Switch to the pad array. */ 347627f7eb2Smrg sptr = NULL; 348627f7eb2Smrg sdim = pdim; 349627f7eb2Smrg for (index_type dim = 0; dim < pdim; dim++) 350627f7eb2Smrg { 351627f7eb2Smrg scount[dim] = pcount[dim]; 352627f7eb2Smrg sextent[dim] = pextent[dim]; 353627f7eb2Smrg sstride[dim] = pstride[dim]; 354627f7eb2Smrg sstride0 = sstride[0]; 355627f7eb2Smrg } 356627f7eb2Smrg } 357627f7eb2Smrg /* We now start again from the beginning of the pad array. */ 358627f7eb2Smrg src = pptr; 359627f7eb2Smrg break; 360627f7eb2Smrg } 361627f7eb2Smrg else 362627f7eb2Smrg { 363627f7eb2Smrg scount[n]++; 364627f7eb2Smrg src += sstride[n]; 365627f7eb2Smrg } 366627f7eb2Smrg } 367627f7eb2Smrg } 368627f7eb2Smrg} 369627f7eb2Smrg 370627f7eb2Smrg#endif' 371