1 /* Implementation of the NORM2 intrinsic
2    Copyright (C) 2010-2018 Free Software Foundation, Inc.
3    Contributed by Tobias Burnus  <burnus@net-b.de>
4 
5 This file is part of the GNU Fortran runtime library (libgfortran).
6 
7 Libgfortran is free software; you can redistribute it and/or
8 modify it under the terms of the GNU General Public
9 License as published by the Free Software Foundation; either
10 version 3 of the License, or (at your option) any later version.
11 
12 Libgfortran is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 GNU General Public License for more details.
16 
17 Under Section 7 of GPL version 3, you are granted additional
18 permissions described in the GCC Runtime Library Exception, version
19 3.1, as published by the Free Software Foundation.
20 
21 You should have received a copy of the GNU General Public License and
22 a copy of the GCC Runtime Library Exception along with this program;
23 see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
24 <http://www.gnu.org/licenses/>.  */
25 
26 #include "libgfortran.h"
27 
28 
29 
30 #if defined (HAVE_GFC_REAL_16) && defined (HAVE_GFC_REAL_16) && (defined(GFC_REAL_16_IS_FLOAT128) || defined(HAVE_SQRTL)) && (defined(GFC_REAL_16_IS_FLOAT128) || defined(HAVE_FABSL))
31 
32 #if defined(GFC_REAL_16_IS_FLOAT128)
33 #define MATHFUNC(funcname) funcname ## q
34 #else
35 #define MATHFUNC(funcname) funcname ## l
36 #endif
37 
38 
39 extern void norm2_r16 (gfc_array_r16 * const restrict,
40 	gfc_array_r16 * const restrict, const index_type * const restrict);
41 export_proto(norm2_r16);
42 
43 void
norm2_r16(gfc_array_r16 * const restrict retarray,gfc_array_r16 * const restrict array,const index_type * const restrict pdim)44 norm2_r16 (gfc_array_r16 * const restrict retarray,
45 	gfc_array_r16 * const restrict array,
46 	const index_type * const restrict pdim)
47 {
48   index_type count[GFC_MAX_DIMENSIONS];
49   index_type extent[GFC_MAX_DIMENSIONS];
50   index_type sstride[GFC_MAX_DIMENSIONS];
51   index_type dstride[GFC_MAX_DIMENSIONS];
52   const GFC_REAL_16 * restrict base;
53   GFC_REAL_16 * restrict dest;
54   index_type rank;
55   index_type n;
56   index_type len;
57   index_type delta;
58   index_type dim;
59   int continue_loop;
60 
61 #ifdef HAVE_BACK_ARG
62   assert(back == 0);
63 #endif
64 
65   /* Make dim zero based to avoid confusion.  */
66   rank = GFC_DESCRIPTOR_RANK (array) - 1;
67   dim = (*pdim) - 1;
68 
69   if (unlikely (dim < 0 || dim > rank))
70     {
71       runtime_error ("Dim argument incorrect in NORM intrinsic: "
72  		     "is %ld, should be between 1 and %ld",
73 		     (long int) dim + 1, (long int) rank + 1);
74     }
75 
76   len = GFC_DESCRIPTOR_EXTENT(array,dim);
77   if (len < 0)
78     len = 0;
79   delta = GFC_DESCRIPTOR_STRIDE(array,dim);
80 
81   for (n = 0; n < dim; n++)
82     {
83       sstride[n] = GFC_DESCRIPTOR_STRIDE(array,n);
84       extent[n] = GFC_DESCRIPTOR_EXTENT(array,n);
85 
86       if (extent[n] < 0)
87 	extent[n] = 0;
88     }
89   for (n = dim; n < rank; n++)
90     {
91       sstride[n] = GFC_DESCRIPTOR_STRIDE(array, n + 1);
92       extent[n] = GFC_DESCRIPTOR_EXTENT(array, n + 1);
93 
94       if (extent[n] < 0)
95 	extent[n] = 0;
96     }
97 
98   if (retarray->base_addr == NULL)
99     {
100       size_t alloc_size, str;
101 
102       for (n = 0; n < rank; n++)
103 	{
104 	  if (n == 0)
105 	    str = 1;
106 	  else
107 	    str = GFC_DESCRIPTOR_STRIDE(retarray,n-1) * extent[n-1];
108 
109 	  GFC_DIMENSION_SET(retarray->dim[n], 0, extent[n] - 1, str);
110 
111 	}
112 
113       retarray->offset = 0;
114       retarray->dtype.rank = rank;
115 
116       alloc_size = GFC_DESCRIPTOR_STRIDE(retarray,rank-1) * extent[rank-1];
117 
118       retarray->base_addr = xmallocarray (alloc_size, sizeof (GFC_REAL_16));
119       if (alloc_size == 0)
120 	{
121 	  /* Make sure we have a zero-sized array.  */
122 	  GFC_DIMENSION_SET(retarray->dim[0], 0, -1, 1);
123 	  return;
124 
125 	}
126     }
127   else
128     {
129       if (rank != GFC_DESCRIPTOR_RANK (retarray))
130 	runtime_error ("rank of return array incorrect in"
131 		       " NORM intrinsic: is %ld, should be %ld",
132 		       (long int) (GFC_DESCRIPTOR_RANK (retarray)),
133 		       (long int) rank);
134 
135       if (unlikely (compile_options.bounds_check))
136 	bounds_ifunction_return ((array_t *) retarray, extent,
137 				 "return value", "NORM");
138     }
139 
140   for (n = 0; n < rank; n++)
141     {
142       count[n] = 0;
143       dstride[n] = GFC_DESCRIPTOR_STRIDE(retarray,n);
144       if (extent[n] <= 0)
145 	return;
146     }
147 
148   base = array->base_addr;
149   dest = retarray->base_addr;
150 
151   continue_loop = 1;
152   while (continue_loop)
153     {
154       const GFC_REAL_16 * restrict src;
155       GFC_REAL_16 result;
156       src = base;
157       {
158 
159 	GFC_REAL_16 scale;
160 	result = 0;
161 	scale = 1;
162 	if (len <= 0)
163 	  *dest = 0;
164 	else
165 	  {
166 	    for (n = 0; n < len; n++, src += delta)
167 	      {
168 
169 	  if (*src != 0)
170 	    {
171 	      GFC_REAL_16 absX, val;
172 	      absX = MATHFUNC(fabs) (*src);
173 	      if (scale < absX)
174 		{
175 		  val = scale / absX;
176 		  result = 1 + result * val * val;
177 		  scale = absX;
178 		}
179 	      else
180 		{
181 		  val = absX / scale;
182 		  result += val * val;
183 		}
184 	    }
185 	      }
186 	    result = scale * MATHFUNC(sqrt) (result);
187 	    *dest = result;
188 	  }
189       }
190       /* Advance to the next element.  */
191       count[0]++;
192       base += sstride[0];
193       dest += dstride[0];
194       n = 0;
195       while (count[n] == extent[n])
196 	{
197 	  /* When we get to the end of a dimension, reset it and increment
198 	     the next dimension.  */
199 	  count[n] = 0;
200 	  /* We could precalculate these products, but this is a less
201 	     frequently used path so probably not worth it.  */
202 	  base -= sstride[n] * extent[n];
203 	  dest -= dstride[n] * extent[n];
204 	  n++;
205 	  if (n >= rank)
206 	    {
207 	      /* Break out of the loop.  */
208 	      continue_loop = 0;
209 	      break;
210 	    }
211 	  else
212 	    {
213 	      count[n]++;
214 	      base += sstride[n];
215 	      dest += dstride[n];
216 	    }
217 	}
218     }
219 }
220 
221 #endif
222