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