xref: /netbsd-src/external/gpl3/gcc.old/dist/libgfortran/runtime/bounds.c (revision 4c3eb207d36f67d31994830c0a694161fc1ca39b)
1*4c3eb207Smrg /* Copyright (C) 2009-2020 Free Software Foundation, Inc.
2627f7eb2Smrg    Contributed by Thomas Koenig
3627f7eb2Smrg 
4627f7eb2Smrg This file is part of the GNU Fortran runtime library (libgfortran).
5627f7eb2Smrg 
6627f7eb2Smrg Libgfortran is free software; you can redistribute it and/or modify
7627f7eb2Smrg it under the terms of the GNU General Public License as published by
8627f7eb2Smrg the Free Software Foundation; either version 3, or (at your option)
9627f7eb2Smrg any later version.
10627f7eb2Smrg 
11627f7eb2Smrg Libgfortran is distributed in the hope that it will be useful,
12627f7eb2Smrg but WITHOUT ANY WARRANTY; without even the implied warranty of
13627f7eb2Smrg MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14627f7eb2Smrg GNU General Public License for more details.
15627f7eb2Smrg 
16627f7eb2Smrg Under Section 7 of GPL version 3, you are granted additional
17627f7eb2Smrg permissions described in the GCC Runtime Library Exception, version
18627f7eb2Smrg 3.1, as published by the Free Software Foundation.
19627f7eb2Smrg 
20627f7eb2Smrg You should have received a copy of the GNU General Public License and
21627f7eb2Smrg a copy of the GCC Runtime Library Exception along with this program;
22627f7eb2Smrg see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
23627f7eb2Smrg <http://www.gnu.org/licenses/>.  */
24627f7eb2Smrg 
25627f7eb2Smrg #include "libgfortran.h"
26627f7eb2Smrg #include <assert.h>
27627f7eb2Smrg 
28627f7eb2Smrg /* Auxiliary functions for bounds checking, mostly to reduce library size.  */
29627f7eb2Smrg 
30627f7eb2Smrg /* Bounds checking for the return values of the iforeach functions (such
31627f7eb2Smrg    as maxloc and minloc).  The extent of ret_array must
32627f7eb2Smrg    must match the rank of array.  */
33627f7eb2Smrg 
34627f7eb2Smrg void
bounds_iforeach_return(array_t * retarray,array_t * array,const char * name)35627f7eb2Smrg bounds_iforeach_return (array_t *retarray, array_t *array, const char *name)
36627f7eb2Smrg {
37627f7eb2Smrg   index_type rank;
38627f7eb2Smrg   index_type ret_rank;
39627f7eb2Smrg   index_type ret_extent;
40627f7eb2Smrg 
41627f7eb2Smrg   ret_rank = GFC_DESCRIPTOR_RANK (retarray);
42627f7eb2Smrg 
43627f7eb2Smrg   /* ret_rank should always be 1, otherwise there is an internal error */
44627f7eb2Smrg   GFC_ASSERT(ret_rank == 1);
45627f7eb2Smrg 
46627f7eb2Smrg   rank = GFC_DESCRIPTOR_RANK (array);
47627f7eb2Smrg   ret_extent = GFC_DESCRIPTOR_EXTENT(retarray,0);
48627f7eb2Smrg   if (ret_extent != rank)
49627f7eb2Smrg     runtime_error ("Incorrect extent in return value of"
50627f7eb2Smrg 		   " %s intrinsic: is %ld, should be %ld",
51627f7eb2Smrg 		   name, (long int) ret_extent, (long int) rank);
52627f7eb2Smrg 
53627f7eb2Smrg }
54627f7eb2Smrg 
55627f7eb2Smrg /* Check the return of functions generated from ifunction.m4.
56627f7eb2Smrg    We check the array descriptor "a" against the extents precomputed
57627f7eb2Smrg    from ifunction.m4, and complain about the argument a_name in the
58627f7eb2Smrg    intrinsic function. */
59627f7eb2Smrg 
60627f7eb2Smrg void
bounds_ifunction_return(array_t * a,const index_type * extent,const char * a_name,const char * intrinsic)61627f7eb2Smrg bounds_ifunction_return (array_t * a, const index_type * extent,
62627f7eb2Smrg 			 const char * a_name, const char * intrinsic)
63627f7eb2Smrg {
64627f7eb2Smrg   int empty;
65627f7eb2Smrg   int rank;
66627f7eb2Smrg   index_type a_size;
67627f7eb2Smrg 
68627f7eb2Smrg   rank = GFC_DESCRIPTOR_RANK (a);
69627f7eb2Smrg   a_size = size0 (a);
70627f7eb2Smrg 
71627f7eb2Smrg   empty = 0;
72627f7eb2Smrg   for (index_type n = 0; n < rank; n++)
73627f7eb2Smrg     {
74627f7eb2Smrg       if (extent[n] == 0)
75627f7eb2Smrg 	empty = 1;
76627f7eb2Smrg     }
77627f7eb2Smrg   if (empty)
78627f7eb2Smrg     {
79627f7eb2Smrg       if (a_size != 0)
80627f7eb2Smrg 	runtime_error ("Incorrect size in %s of %s"
81627f7eb2Smrg 		       " intrinsic: should be zero-sized",
82627f7eb2Smrg 		       a_name, intrinsic);
83627f7eb2Smrg     }
84627f7eb2Smrg   else
85627f7eb2Smrg     {
86627f7eb2Smrg       if (a_size == 0)
87627f7eb2Smrg 	runtime_error ("Incorrect size of %s in %s"
88627f7eb2Smrg 		       " intrinsic: should not be zero-sized",
89627f7eb2Smrg 		       a_name, intrinsic);
90627f7eb2Smrg 
91627f7eb2Smrg       for (index_type n = 0; n < rank; n++)
92627f7eb2Smrg 	{
93627f7eb2Smrg 	  index_type a_extent;
94627f7eb2Smrg 	  a_extent = GFC_DESCRIPTOR_EXTENT(a, n);
95627f7eb2Smrg 	  if (a_extent != extent[n])
96627f7eb2Smrg 	    runtime_error("Incorrect extent in %s of %s"
97627f7eb2Smrg 			  " intrinsic in dimension %ld: is %ld,"
98627f7eb2Smrg 			  " should be %ld", a_name, intrinsic, (long int) n + 1,
99627f7eb2Smrg 			  (long int) a_extent, (long int) extent[n]);
100627f7eb2Smrg 
101627f7eb2Smrg 	}
102627f7eb2Smrg     }
103627f7eb2Smrg }
104627f7eb2Smrg 
105627f7eb2Smrg /* Check that two arrays have equal extents, or are both zero-sized.  Abort
106627f7eb2Smrg    with a runtime error if this is not the case.  Complain that a has the
107627f7eb2Smrg    wrong size.  */
108627f7eb2Smrg 
109627f7eb2Smrg void
bounds_equal_extents(array_t * a,array_t * b,const char * a_name,const char * intrinsic)110627f7eb2Smrg bounds_equal_extents (array_t *a, array_t *b, const char *a_name,
111627f7eb2Smrg 		      const char *intrinsic)
112627f7eb2Smrg {
113627f7eb2Smrg   index_type a_size, b_size, n;
114627f7eb2Smrg 
115627f7eb2Smrg   assert (GFC_DESCRIPTOR_RANK(a) == GFC_DESCRIPTOR_RANK(b));
116627f7eb2Smrg 
117627f7eb2Smrg   a_size = size0 (a);
118627f7eb2Smrg   b_size = size0 (b);
119627f7eb2Smrg 
120627f7eb2Smrg   if (b_size == 0)
121627f7eb2Smrg     {
122627f7eb2Smrg       if (a_size != 0)
123627f7eb2Smrg 	runtime_error ("Incorrect size of %s in %s"
124627f7eb2Smrg 		       " intrinsic: should be zero-sized",
125627f7eb2Smrg 		       a_name, intrinsic);
126627f7eb2Smrg     }
127627f7eb2Smrg   else
128627f7eb2Smrg     {
129627f7eb2Smrg       if (a_size == 0)
130627f7eb2Smrg 	runtime_error ("Incorrect size of %s of %s"
131627f7eb2Smrg 		       " intrinsic: Should not be zero-sized",
132627f7eb2Smrg 		       a_name, intrinsic);
133627f7eb2Smrg 
134627f7eb2Smrg       for (n = 0; n < GFC_DESCRIPTOR_RANK (b); n++)
135627f7eb2Smrg 	{
136627f7eb2Smrg 	  index_type a_extent, b_extent;
137627f7eb2Smrg 
138627f7eb2Smrg 	  a_extent = GFC_DESCRIPTOR_EXTENT(a, n);
139627f7eb2Smrg 	  b_extent = GFC_DESCRIPTOR_EXTENT(b, n);
140627f7eb2Smrg 	  if (a_extent != b_extent)
141627f7eb2Smrg 	    runtime_error("Incorrect extent in %s of %s"
142627f7eb2Smrg 			  " intrinsic in dimension %ld: is %ld,"
143627f7eb2Smrg 			  " should be %ld", a_name, intrinsic, (long int) n + 1,
144627f7eb2Smrg 			  (long int) a_extent, (long int) b_extent);
145627f7eb2Smrg 	}
146627f7eb2Smrg     }
147627f7eb2Smrg }
148627f7eb2Smrg 
149627f7eb2Smrg /* Check that the extents of a and b agree, except that a has a missing
150627f7eb2Smrg    dimension in argument which.  Complain about a if anything is wrong.  */
151627f7eb2Smrg 
152627f7eb2Smrg void
bounds_reduced_extents(array_t * a,array_t * b,int which,const char * a_name,const char * intrinsic)153627f7eb2Smrg bounds_reduced_extents (array_t *a, array_t *b, int which, const char *a_name,
154627f7eb2Smrg 		      const char *intrinsic)
155627f7eb2Smrg {
156627f7eb2Smrg 
157627f7eb2Smrg   index_type i, n, a_size, b_size;
158627f7eb2Smrg 
159627f7eb2Smrg   assert (GFC_DESCRIPTOR_RANK(a) == GFC_DESCRIPTOR_RANK(b) - 1);
160627f7eb2Smrg 
161627f7eb2Smrg   a_size = size0 (a);
162627f7eb2Smrg   b_size = size0 (b);
163627f7eb2Smrg 
164627f7eb2Smrg   if (b_size == 0)
165627f7eb2Smrg     {
166627f7eb2Smrg       if (a_size != 0)
167627f7eb2Smrg 	runtime_error ("Incorrect size in %s of %s"
168627f7eb2Smrg 		       " intrinsic: should not be zero-sized",
169627f7eb2Smrg 		       a_name, intrinsic);
170627f7eb2Smrg     }
171627f7eb2Smrg   else
172627f7eb2Smrg     {
173627f7eb2Smrg       if (a_size == 0)
174627f7eb2Smrg 	runtime_error ("Incorrect size of %s of %s"
175627f7eb2Smrg 		       " intrinsic: should be zero-sized",
176627f7eb2Smrg 		       a_name, intrinsic);
177627f7eb2Smrg 
178627f7eb2Smrg       i = 0;
179627f7eb2Smrg       for (n = 0; n < GFC_DESCRIPTOR_RANK (b); n++)
180627f7eb2Smrg 	{
181627f7eb2Smrg 	  index_type a_extent, b_extent;
182627f7eb2Smrg 
183627f7eb2Smrg 	  if (n != which)
184627f7eb2Smrg 	    {
185627f7eb2Smrg 	      a_extent = GFC_DESCRIPTOR_EXTENT(a, i);
186627f7eb2Smrg 	      b_extent = GFC_DESCRIPTOR_EXTENT(b, n);
187627f7eb2Smrg 	      if (a_extent != b_extent)
188627f7eb2Smrg 		runtime_error("Incorrect extent in %s of %s"
189627f7eb2Smrg 			      " intrinsic in dimension %ld: is %ld,"
190627f7eb2Smrg 			      " should be %ld", a_name, intrinsic, (long int) i + 1,
191627f7eb2Smrg 			      (long int) a_extent, (long int) b_extent);
192627f7eb2Smrg 	      i++;
193627f7eb2Smrg 	    }
194627f7eb2Smrg 	}
195627f7eb2Smrg     }
196627f7eb2Smrg }
197627f7eb2Smrg 
198627f7eb2Smrg /* count_0 - count all the true elements in an array.  The front
199627f7eb2Smrg    end usually inlines this, we need this for bounds checking
200627f7eb2Smrg    for unpack.  */
201627f7eb2Smrg 
count_0(const gfc_array_l1 * array)202627f7eb2Smrg index_type count_0 (const gfc_array_l1 * array)
203627f7eb2Smrg {
204627f7eb2Smrg   const GFC_LOGICAL_1 * restrict base;
205627f7eb2Smrg   index_type rank;
206627f7eb2Smrg   int kind;
207627f7eb2Smrg   int continue_loop;
208627f7eb2Smrg   index_type count[GFC_MAX_DIMENSIONS];
209627f7eb2Smrg   index_type extent[GFC_MAX_DIMENSIONS];
210627f7eb2Smrg   index_type sstride[GFC_MAX_DIMENSIONS];
211627f7eb2Smrg   index_type result;
212627f7eb2Smrg   index_type n;
213627f7eb2Smrg 
214627f7eb2Smrg   rank = GFC_DESCRIPTOR_RANK (array);
215627f7eb2Smrg   kind = GFC_DESCRIPTOR_SIZE (array);
216627f7eb2Smrg 
217627f7eb2Smrg   base = array->base_addr;
218627f7eb2Smrg 
219627f7eb2Smrg   if (kind == 1 || kind == 2 || kind == 4 || kind == 8
220627f7eb2Smrg #ifdef HAVE_GFC_LOGICAL_16
221627f7eb2Smrg       || kind == 16
222627f7eb2Smrg #endif
223627f7eb2Smrg     )
224627f7eb2Smrg     {
225627f7eb2Smrg       if (base)
226627f7eb2Smrg 	base = GFOR_POINTER_TO_L1 (base, kind);
227627f7eb2Smrg     }
228627f7eb2Smrg   else
229627f7eb2Smrg     internal_error (NULL, "Funny sized logical array in count_0");
230627f7eb2Smrg 
231627f7eb2Smrg   for (n = 0; n < rank; n++)
232627f7eb2Smrg     {
233627f7eb2Smrg       sstride[n] = GFC_DESCRIPTOR_STRIDE_BYTES(array,n);
234627f7eb2Smrg       extent[n] = GFC_DESCRIPTOR_EXTENT(array,n);
235627f7eb2Smrg       count[n] = 0;
236627f7eb2Smrg 
237627f7eb2Smrg       if (extent[n] <= 0)
238627f7eb2Smrg 	return 0;
239627f7eb2Smrg     }
240627f7eb2Smrg 
241627f7eb2Smrg   result = 0;
242627f7eb2Smrg   continue_loop = 1;
243627f7eb2Smrg   while (continue_loop)
244627f7eb2Smrg     {
245627f7eb2Smrg       if (*base)
246627f7eb2Smrg 	result ++;
247627f7eb2Smrg 
248627f7eb2Smrg       count[0]++;
249627f7eb2Smrg       base += sstride[0];
250627f7eb2Smrg       n = 0;
251627f7eb2Smrg       while (count[n] == extent[n])
252627f7eb2Smrg 	{
253627f7eb2Smrg 	  count[n] = 0;
254627f7eb2Smrg 	  base -= sstride[n] * extent[n];
255627f7eb2Smrg 	  n++;
256627f7eb2Smrg 	  if (n == rank)
257627f7eb2Smrg 	    {
258627f7eb2Smrg 	      continue_loop = 0;
259627f7eb2Smrg 	      break;
260627f7eb2Smrg 	    }
261627f7eb2Smrg 	  else
262627f7eb2Smrg 	    {
263627f7eb2Smrg 	      count[n]++;
264627f7eb2Smrg 	      base += sstride[n];
265627f7eb2Smrg 	    }
266627f7eb2Smrg 	}
267627f7eb2Smrg     }
268627f7eb2Smrg   return result;
269627f7eb2Smrg }
270