xref: /netbsd-src/external/gpl3/gcc.old/dist/libgfortran/generated/spread_i16.c (revision 4c3eb207d36f67d31994830c0a694161fc1ca39b)
1627f7eb2Smrg /* Special implementation of the SPREAD intrinsic
2*4c3eb207Smrg    Copyright (C) 2008-2020 Free Software Foundation, Inc.
3627f7eb2Smrg    Contributed by Thomas Koenig <tkoenig@gcc.gnu.org>, based on
4627f7eb2Smrg    spread_generic.c written by Paul Brook <paul@nowt.org>
5627f7eb2Smrg 
6627f7eb2Smrg This file is part of the GNU Fortran runtime library (libgfortran).
7627f7eb2Smrg 
8627f7eb2Smrg Libgfortran is free software; you can redistribute it and/or
9627f7eb2Smrg modify it under the terms of the GNU General Public
10627f7eb2Smrg License as published by the Free Software Foundation; either
11627f7eb2Smrg version 3 of the License, or (at your option) any later version.
12627f7eb2Smrg 
13627f7eb2Smrg Ligbfortran is distributed in the hope that it will be useful,
14627f7eb2Smrg but WITHOUT ANY WARRANTY; without even the implied warranty of
15627f7eb2Smrg MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16627f7eb2Smrg GNU General Public License for more details.
17627f7eb2Smrg 
18627f7eb2Smrg Under Section 7 of GPL version 3, you are granted additional
19627f7eb2Smrg permissions described in the GCC Runtime Library Exception, version
20627f7eb2Smrg 3.1, as published by the Free Software Foundation.
21627f7eb2Smrg 
22627f7eb2Smrg You should have received a copy of the GNU General Public License and
23627f7eb2Smrg a copy of the GCC Runtime Library Exception along with this program;
24627f7eb2Smrg see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
25627f7eb2Smrg <http://www.gnu.org/licenses/>.  */
26627f7eb2Smrg 
27627f7eb2Smrg #include "libgfortran.h"
28627f7eb2Smrg #include <string.h>
29627f7eb2Smrg 
30627f7eb2Smrg 
31627f7eb2Smrg #if defined (HAVE_GFC_INTEGER_16)
32627f7eb2Smrg 
33627f7eb2Smrg void
spread_i16(gfc_array_i16 * ret,const gfc_array_i16 * source,const index_type along,const index_type pncopies)34627f7eb2Smrg spread_i16 (gfc_array_i16 *ret, const gfc_array_i16 *source,
35627f7eb2Smrg 		 const index_type along, const index_type pncopies)
36627f7eb2Smrg {
37627f7eb2Smrg   /* r.* indicates the return array.  */
38627f7eb2Smrg   index_type rstride[GFC_MAX_DIMENSIONS];
39627f7eb2Smrg   index_type rstride0;
40627f7eb2Smrg   index_type rdelta = 0;
41627f7eb2Smrg   index_type rrank;
42627f7eb2Smrg   index_type rs;
43627f7eb2Smrg   GFC_INTEGER_16 *rptr;
44627f7eb2Smrg   GFC_INTEGER_16 * restrict dest;
45627f7eb2Smrg   /* s.* indicates the source array.  */
46627f7eb2Smrg   index_type sstride[GFC_MAX_DIMENSIONS];
47627f7eb2Smrg   index_type sstride0;
48627f7eb2Smrg   index_type srank;
49627f7eb2Smrg   const GFC_INTEGER_16 *sptr;
50627f7eb2Smrg 
51627f7eb2Smrg   index_type count[GFC_MAX_DIMENSIONS];
52627f7eb2Smrg   index_type extent[GFC_MAX_DIMENSIONS];
53627f7eb2Smrg   index_type n;
54627f7eb2Smrg   index_type dim;
55627f7eb2Smrg   index_type ncopies;
56627f7eb2Smrg 
57627f7eb2Smrg   srank = GFC_DESCRIPTOR_RANK(source);
58627f7eb2Smrg 
59627f7eb2Smrg   rrank = srank + 1;
60627f7eb2Smrg   if (rrank > GFC_MAX_DIMENSIONS)
61627f7eb2Smrg     runtime_error ("return rank too large in spread()");
62627f7eb2Smrg 
63627f7eb2Smrg   if (along > rrank)
64627f7eb2Smrg       runtime_error ("dim outside of rank in spread()");
65627f7eb2Smrg 
66627f7eb2Smrg   ncopies = pncopies;
67627f7eb2Smrg 
68627f7eb2Smrg   if (ret->base_addr == NULL)
69627f7eb2Smrg     {
70627f7eb2Smrg 
71627f7eb2Smrg       size_t ub, stride;
72627f7eb2Smrg 
73627f7eb2Smrg       /* The front end has signalled that we need to populate the
74627f7eb2Smrg 	 return array descriptor.  */
75627f7eb2Smrg       ret->dtype.rank = rrank;
76627f7eb2Smrg 
77627f7eb2Smrg       dim = 0;
78627f7eb2Smrg       rs = 1;
79627f7eb2Smrg       for (n = 0; n < rrank; n++)
80627f7eb2Smrg 	{
81627f7eb2Smrg 	  stride = rs;
82627f7eb2Smrg 	  if (n == along - 1)
83627f7eb2Smrg 	    {
84627f7eb2Smrg 	      ub = ncopies - 1;
85627f7eb2Smrg 	      rdelta = rs;
86627f7eb2Smrg 	      rs *= ncopies;
87627f7eb2Smrg 	    }
88627f7eb2Smrg 	  else
89627f7eb2Smrg 	    {
90627f7eb2Smrg 	      count[dim] = 0;
91627f7eb2Smrg 	      extent[dim] = GFC_DESCRIPTOR_EXTENT(source,dim);
92627f7eb2Smrg 	      sstride[dim] = GFC_DESCRIPTOR_STRIDE(source,dim);
93627f7eb2Smrg 	      rstride[dim] = rs;
94627f7eb2Smrg 
95627f7eb2Smrg 	      ub = extent[dim] - 1;
96627f7eb2Smrg 	      rs *= extent[dim];
97627f7eb2Smrg 	      dim++;
98627f7eb2Smrg 	    }
99627f7eb2Smrg 	  GFC_DIMENSION_SET(ret->dim[n], 0, ub, stride);
100627f7eb2Smrg 	}
101627f7eb2Smrg       ret->offset = 0;
102627f7eb2Smrg 
103627f7eb2Smrg       /* xmallocarray allocates a single byte for zero size.  */
104627f7eb2Smrg       ret->base_addr = xmallocarray (rs, sizeof(GFC_INTEGER_16));
105627f7eb2Smrg       if (rs <= 0)
106627f7eb2Smrg         return;
107627f7eb2Smrg     }
108627f7eb2Smrg   else
109627f7eb2Smrg     {
110627f7eb2Smrg       int zero_sized;
111627f7eb2Smrg 
112627f7eb2Smrg       zero_sized = 0;
113627f7eb2Smrg 
114627f7eb2Smrg       dim = 0;
115627f7eb2Smrg       if (GFC_DESCRIPTOR_RANK(ret) != rrank)
116627f7eb2Smrg 	runtime_error ("rank mismatch in spread()");
117627f7eb2Smrg 
118627f7eb2Smrg       if (unlikely (compile_options.bounds_check))
119627f7eb2Smrg 	{
120627f7eb2Smrg 	  for (n = 0; n < rrank; n++)
121627f7eb2Smrg 	    {
122627f7eb2Smrg 	      index_type ret_extent;
123627f7eb2Smrg 
124627f7eb2Smrg 	      ret_extent = GFC_DESCRIPTOR_EXTENT(ret,n);
125627f7eb2Smrg 	      if (n == along - 1)
126627f7eb2Smrg 		{
127627f7eb2Smrg 		  rdelta = GFC_DESCRIPTOR_STRIDE(ret,n);
128627f7eb2Smrg 
129627f7eb2Smrg 		  if (ret_extent != ncopies)
130627f7eb2Smrg 		    runtime_error("Incorrect extent in return value of SPREAD"
131627f7eb2Smrg 				  " intrinsic in dimension %ld: is %ld,"
132627f7eb2Smrg 				  " should be %ld", (long int) n+1,
133627f7eb2Smrg 				  (long int) ret_extent, (long int) ncopies);
134627f7eb2Smrg 		}
135627f7eb2Smrg 	      else
136627f7eb2Smrg 		{
137627f7eb2Smrg 		  count[dim] = 0;
138627f7eb2Smrg 		  extent[dim] = GFC_DESCRIPTOR_EXTENT(source,dim);
139627f7eb2Smrg 		  if (ret_extent != extent[dim])
140627f7eb2Smrg 		    runtime_error("Incorrect extent in return value of SPREAD"
141627f7eb2Smrg 				  " intrinsic in dimension %ld: is %ld,"
142627f7eb2Smrg 				  " should be %ld", (long int) n+1,
143627f7eb2Smrg 				  (long int) ret_extent,
144627f7eb2Smrg 				  (long int) extent[dim]);
145627f7eb2Smrg 
146627f7eb2Smrg 		  if (extent[dim] <= 0)
147627f7eb2Smrg 		    zero_sized = 1;
148627f7eb2Smrg 		  sstride[dim] = GFC_DESCRIPTOR_STRIDE(source,dim);
149627f7eb2Smrg 		  rstride[dim] = GFC_DESCRIPTOR_STRIDE(ret,n);
150627f7eb2Smrg 		  dim++;
151627f7eb2Smrg 		}
152627f7eb2Smrg 	    }
153627f7eb2Smrg 	}
154627f7eb2Smrg       else
155627f7eb2Smrg 	{
156627f7eb2Smrg 	  for (n = 0; n < rrank; n++)
157627f7eb2Smrg 	    {
158627f7eb2Smrg 	      if (n == along - 1)
159627f7eb2Smrg 		{
160627f7eb2Smrg 		  rdelta = GFC_DESCRIPTOR_STRIDE(ret,n);
161627f7eb2Smrg 		}
162627f7eb2Smrg 	      else
163627f7eb2Smrg 		{
164627f7eb2Smrg 		  count[dim] = 0;
165627f7eb2Smrg 		  extent[dim] = GFC_DESCRIPTOR_EXTENT(source,dim);
166627f7eb2Smrg 		  if (extent[dim] <= 0)
167627f7eb2Smrg 		    zero_sized = 1;
168627f7eb2Smrg 		  sstride[dim] = GFC_DESCRIPTOR_STRIDE(source,dim);
169627f7eb2Smrg 		  rstride[dim] = GFC_DESCRIPTOR_STRIDE(ret,n);
170627f7eb2Smrg 		  dim++;
171627f7eb2Smrg 		}
172627f7eb2Smrg 	    }
173627f7eb2Smrg 	}
174627f7eb2Smrg 
175627f7eb2Smrg       if (zero_sized)
176627f7eb2Smrg 	return;
177627f7eb2Smrg 
178627f7eb2Smrg       if (sstride[0] == 0)
179627f7eb2Smrg 	sstride[0] = 1;
180627f7eb2Smrg     }
181627f7eb2Smrg   sstride0 = sstride[0];
182627f7eb2Smrg   rstride0 = rstride[0];
183627f7eb2Smrg   rptr = ret->base_addr;
184627f7eb2Smrg   sptr = source->base_addr;
185627f7eb2Smrg 
186627f7eb2Smrg   while (sptr)
187627f7eb2Smrg     {
188627f7eb2Smrg       /* Spread this element.  */
189627f7eb2Smrg       dest = rptr;
190627f7eb2Smrg       for (n = 0; n < ncopies; n++)
191627f7eb2Smrg         {
192627f7eb2Smrg 	  *dest = *sptr;
193627f7eb2Smrg           dest += rdelta;
194627f7eb2Smrg         }
195627f7eb2Smrg       /* Advance to the next element.  */
196627f7eb2Smrg       sptr += sstride0;
197627f7eb2Smrg       rptr += rstride0;
198627f7eb2Smrg       count[0]++;
199627f7eb2Smrg       n = 0;
200627f7eb2Smrg       while (count[n] == extent[n])
201627f7eb2Smrg         {
202627f7eb2Smrg           /* When we get to the end of a dimension, reset it and increment
203627f7eb2Smrg              the next dimension.  */
204627f7eb2Smrg           count[n] = 0;
205627f7eb2Smrg           /* We could precalculate these products, but this is a less
206627f7eb2Smrg              frequently used path so probably not worth it.  */
207627f7eb2Smrg           sptr -= sstride[n] * extent[n];
208627f7eb2Smrg           rptr -= rstride[n] * extent[n];
209627f7eb2Smrg           n++;
210627f7eb2Smrg           if (n >= srank)
211627f7eb2Smrg             {
212627f7eb2Smrg               /* Break out of the loop.  */
213627f7eb2Smrg               sptr = NULL;
214627f7eb2Smrg               break;
215627f7eb2Smrg             }
216627f7eb2Smrg           else
217627f7eb2Smrg             {
218627f7eb2Smrg               count[n]++;
219627f7eb2Smrg               sptr += sstride[n];
220627f7eb2Smrg               rptr += rstride[n];
221627f7eb2Smrg             }
222627f7eb2Smrg         }
223627f7eb2Smrg     }
224627f7eb2Smrg }
225627f7eb2Smrg 
226627f7eb2Smrg /* This version of spread_internal treats the special case of a scalar
227627f7eb2Smrg    source.  This is much simpler than the more general case above.  */
228627f7eb2Smrg 
229627f7eb2Smrg void
spread_scalar_i16(gfc_array_i16 * ret,const GFC_INTEGER_16 * source,const index_type along,const index_type ncopies)230627f7eb2Smrg spread_scalar_i16 (gfc_array_i16 *ret, const GFC_INTEGER_16 *source,
231627f7eb2Smrg 			const index_type along, const index_type ncopies)
232627f7eb2Smrg {
233627f7eb2Smrg   GFC_INTEGER_16 * restrict dest;
234627f7eb2Smrg   index_type stride;
235627f7eb2Smrg 
236627f7eb2Smrg   if (GFC_DESCRIPTOR_RANK (ret) != 1)
237627f7eb2Smrg     runtime_error ("incorrect destination rank in spread()");
238627f7eb2Smrg 
239627f7eb2Smrg   if (along > 1)
240627f7eb2Smrg     runtime_error ("dim outside of rank in spread()");
241627f7eb2Smrg 
242627f7eb2Smrg   if (ret->base_addr == NULL)
243627f7eb2Smrg     {
244627f7eb2Smrg       ret->base_addr = xmallocarray (ncopies, sizeof (GFC_INTEGER_16));
245627f7eb2Smrg       ret->offset = 0;
246627f7eb2Smrg       GFC_DIMENSION_SET(ret->dim[0], 0, ncopies - 1, 1);
247627f7eb2Smrg     }
248627f7eb2Smrg   else
249627f7eb2Smrg     {
250627f7eb2Smrg       if (ncopies - 1 > (GFC_DESCRIPTOR_EXTENT(ret,0) - 1)
251627f7eb2Smrg 			   / GFC_DESCRIPTOR_STRIDE(ret,0))
252627f7eb2Smrg 	runtime_error ("dim too large in spread()");
253627f7eb2Smrg     }
254627f7eb2Smrg 
255627f7eb2Smrg   dest = ret->base_addr;
256627f7eb2Smrg   stride = GFC_DESCRIPTOR_STRIDE(ret,0);
257627f7eb2Smrg 
258627f7eb2Smrg   for (index_type n = 0; n < ncopies; n++)
259627f7eb2Smrg     {
260627f7eb2Smrg       *dest = *source;
261627f7eb2Smrg       dest += stride;
262627f7eb2Smrg     }
263627f7eb2Smrg }
264627f7eb2Smrg 
265627f7eb2Smrg #endif
266627f7eb2Smrg 
267