xref: /netbsd-src/external/gpl3/gcc/dist/libgfortran/generated/norm2_r8.c (revision b1e838363e3c6fc78a55519254d99869742dd33c)
1181254a7Smrg /* Implementation of the NORM2 intrinsic
2*b1e83836Smrg    Copyright (C) 2010-2022 Free Software Foundation, Inc.
3181254a7Smrg    Contributed by Tobias Burnus  <burnus@net-b.de>
4181254a7Smrg 
5181254a7Smrg This file is part of the GNU Fortran runtime library (libgfortran).
6181254a7Smrg 
7181254a7Smrg Libgfortran is free software; you can redistribute it and/or
8181254a7Smrg modify it under the terms of the GNU General Public
9181254a7Smrg License as published by the Free Software Foundation; either
10181254a7Smrg version 3 of the License, or (at your option) any later version.
11181254a7Smrg 
12181254a7Smrg Libgfortran is distributed in the hope that it will be useful,
13181254a7Smrg but WITHOUT ANY WARRANTY; without even the implied warranty of
14181254a7Smrg MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15181254a7Smrg GNU General Public License for more details.
16181254a7Smrg 
17181254a7Smrg Under Section 7 of GPL version 3, you are granted additional
18181254a7Smrg permissions described in the GCC Runtime Library Exception, version
19181254a7Smrg 3.1, as published by the Free Software Foundation.
20181254a7Smrg 
21181254a7Smrg You should have received a copy of the GNU General Public License and
22181254a7Smrg a copy of the GCC Runtime Library Exception along with this program;
23181254a7Smrg see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
24181254a7Smrg <http://www.gnu.org/licenses/>.  */
25181254a7Smrg 
26181254a7Smrg #include "libgfortran.h"
27181254a7Smrg 
28181254a7Smrg 
29181254a7Smrg 
30181254a7Smrg #if defined (HAVE_GFC_REAL_8) && defined (HAVE_GFC_REAL_8) && defined (HAVE_SQRT) && defined (HAVE_FABS)
31181254a7Smrg 
32181254a7Smrg #define MATHFUNC(funcname) funcname
33181254a7Smrg 
34181254a7Smrg 
35181254a7Smrg extern void norm2_r8 (gfc_array_r8 * const restrict,
36181254a7Smrg 	gfc_array_r8 * const restrict, const index_type * const restrict);
37181254a7Smrg export_proto(norm2_r8);
38181254a7Smrg 
39181254a7Smrg void
norm2_r8(gfc_array_r8 * const restrict retarray,gfc_array_r8 * const restrict array,const index_type * const restrict pdim)40181254a7Smrg norm2_r8 (gfc_array_r8 * const restrict retarray,
41181254a7Smrg 	gfc_array_r8 * const restrict array,
42181254a7Smrg 	const index_type * const restrict pdim)
43181254a7Smrg {
44181254a7Smrg   index_type count[GFC_MAX_DIMENSIONS];
45181254a7Smrg   index_type extent[GFC_MAX_DIMENSIONS];
46181254a7Smrg   index_type sstride[GFC_MAX_DIMENSIONS];
47181254a7Smrg   index_type dstride[GFC_MAX_DIMENSIONS];
48181254a7Smrg   const GFC_REAL_8 * restrict base;
49181254a7Smrg   GFC_REAL_8 * restrict dest;
50181254a7Smrg   index_type rank;
51181254a7Smrg   index_type n;
52181254a7Smrg   index_type len;
53181254a7Smrg   index_type delta;
54181254a7Smrg   index_type dim;
55181254a7Smrg   int continue_loop;
56181254a7Smrg 
57181254a7Smrg   /* Make dim zero based to avoid confusion.  */
58181254a7Smrg   rank = GFC_DESCRIPTOR_RANK (array) - 1;
59181254a7Smrg   dim = (*pdim) - 1;
60181254a7Smrg 
61181254a7Smrg   if (unlikely (dim < 0 || dim > rank))
62181254a7Smrg     {
63181254a7Smrg       runtime_error ("Dim argument incorrect in NORM intrinsic: "
64181254a7Smrg  		     "is %ld, should be between 1 and %ld",
65181254a7Smrg 		     (long int) dim + 1, (long int) rank + 1);
66181254a7Smrg     }
67181254a7Smrg 
68181254a7Smrg   len = GFC_DESCRIPTOR_EXTENT(array,dim);
69181254a7Smrg   if (len < 0)
70181254a7Smrg     len = 0;
71181254a7Smrg   delta = GFC_DESCRIPTOR_STRIDE(array,dim);
72181254a7Smrg 
73181254a7Smrg   for (n = 0; n < dim; n++)
74181254a7Smrg     {
75181254a7Smrg       sstride[n] = GFC_DESCRIPTOR_STRIDE(array,n);
76181254a7Smrg       extent[n] = GFC_DESCRIPTOR_EXTENT(array,n);
77181254a7Smrg 
78181254a7Smrg       if (extent[n] < 0)
79181254a7Smrg 	extent[n] = 0;
80181254a7Smrg     }
81181254a7Smrg   for (n = dim; n < rank; n++)
82181254a7Smrg     {
83181254a7Smrg       sstride[n] = GFC_DESCRIPTOR_STRIDE(array, n + 1);
84181254a7Smrg       extent[n] = GFC_DESCRIPTOR_EXTENT(array, n + 1);
85181254a7Smrg 
86181254a7Smrg       if (extent[n] < 0)
87181254a7Smrg 	extent[n] = 0;
88181254a7Smrg     }
89181254a7Smrg 
90181254a7Smrg   if (retarray->base_addr == NULL)
91181254a7Smrg     {
92181254a7Smrg       size_t alloc_size, str;
93181254a7Smrg 
94181254a7Smrg       for (n = 0; n < rank; n++)
95181254a7Smrg 	{
96181254a7Smrg 	  if (n == 0)
97181254a7Smrg 	    str = 1;
98181254a7Smrg 	  else
99181254a7Smrg 	    str = GFC_DESCRIPTOR_STRIDE(retarray,n-1) * extent[n-1];
100181254a7Smrg 
101181254a7Smrg 	  GFC_DIMENSION_SET(retarray->dim[n], 0, extent[n] - 1, str);
102181254a7Smrg 
103181254a7Smrg 	}
104181254a7Smrg 
105181254a7Smrg       retarray->offset = 0;
106181254a7Smrg       retarray->dtype.rank = rank;
107181254a7Smrg 
108181254a7Smrg       alloc_size = GFC_DESCRIPTOR_STRIDE(retarray,rank-1) * extent[rank-1];
109181254a7Smrg 
110181254a7Smrg       retarray->base_addr = xmallocarray (alloc_size, sizeof (GFC_REAL_8));
111181254a7Smrg       if (alloc_size == 0)
112181254a7Smrg 	{
113181254a7Smrg 	  /* Make sure we have a zero-sized array.  */
114181254a7Smrg 	  GFC_DIMENSION_SET(retarray->dim[0], 0, -1, 1);
115181254a7Smrg 	  return;
116181254a7Smrg 
117181254a7Smrg 	}
118181254a7Smrg     }
119181254a7Smrg   else
120181254a7Smrg     {
121181254a7Smrg       if (rank != GFC_DESCRIPTOR_RANK (retarray))
122181254a7Smrg 	runtime_error ("rank of return array incorrect in"
123181254a7Smrg 		       " NORM intrinsic: is %ld, should be %ld",
124181254a7Smrg 		       (long int) (GFC_DESCRIPTOR_RANK (retarray)),
125181254a7Smrg 		       (long int) rank);
126181254a7Smrg 
127181254a7Smrg       if (unlikely (compile_options.bounds_check))
128181254a7Smrg 	bounds_ifunction_return ((array_t *) retarray, extent,
129181254a7Smrg 				 "return value", "NORM");
130181254a7Smrg     }
131181254a7Smrg 
132181254a7Smrg   for (n = 0; n < rank; n++)
133181254a7Smrg     {
134181254a7Smrg       count[n] = 0;
135181254a7Smrg       dstride[n] = GFC_DESCRIPTOR_STRIDE(retarray,n);
136181254a7Smrg       if (extent[n] <= 0)
137181254a7Smrg 	return;
138181254a7Smrg     }
139181254a7Smrg 
140181254a7Smrg   base = array->base_addr;
141181254a7Smrg   dest = retarray->base_addr;
142181254a7Smrg 
143181254a7Smrg   continue_loop = 1;
144181254a7Smrg   while (continue_loop)
145181254a7Smrg     {
146181254a7Smrg       const GFC_REAL_8 * restrict src;
147181254a7Smrg       GFC_REAL_8 result;
148181254a7Smrg       src = base;
149181254a7Smrg       {
150181254a7Smrg 
151181254a7Smrg 	GFC_REAL_8 scale;
152181254a7Smrg 	result = 0;
153181254a7Smrg 	scale = 1;
154181254a7Smrg 	if (len <= 0)
155181254a7Smrg 	  *dest = 0;
156181254a7Smrg 	else
157181254a7Smrg 	  {
158181254a7Smrg #if ! defined HAVE_BACK_ARG
159181254a7Smrg 	    for (n = 0; n < len; n++, src += delta)
160181254a7Smrg 	      {
161181254a7Smrg #endif
162181254a7Smrg 
163181254a7Smrg 	  if (*src != 0)
164181254a7Smrg 	    {
165181254a7Smrg 	      GFC_REAL_8 absX, val;
166181254a7Smrg 	      absX = MATHFUNC(fabs) (*src);
167181254a7Smrg 	      if (scale < absX)
168181254a7Smrg 		{
169181254a7Smrg 		  val = scale / absX;
170181254a7Smrg 		  result = 1 + result * val * val;
171181254a7Smrg 		  scale = absX;
172181254a7Smrg 		}
173181254a7Smrg 	      else
174181254a7Smrg 		{
175181254a7Smrg 		  val = absX / scale;
176181254a7Smrg 		  result += val * val;
177181254a7Smrg 		}
178181254a7Smrg 	    }
179181254a7Smrg 	      }
180181254a7Smrg 	    result = scale * MATHFUNC(sqrt) (result);
181181254a7Smrg 	    *dest = result;
182181254a7Smrg 	  }
183181254a7Smrg       }
184181254a7Smrg       /* Advance to the next element.  */
185181254a7Smrg       count[0]++;
186181254a7Smrg       base += sstride[0];
187181254a7Smrg       dest += dstride[0];
188181254a7Smrg       n = 0;
189181254a7Smrg       while (count[n] == extent[n])
190181254a7Smrg 	{
191181254a7Smrg 	  /* When we get to the end of a dimension, reset it and increment
192181254a7Smrg 	     the next dimension.  */
193181254a7Smrg 	  count[n] = 0;
194181254a7Smrg 	  /* We could precalculate these products, but this is a less
195181254a7Smrg 	     frequently used path so probably not worth it.  */
196181254a7Smrg 	  base -= sstride[n] * extent[n];
197181254a7Smrg 	  dest -= dstride[n] * extent[n];
198181254a7Smrg 	  n++;
199181254a7Smrg 	  if (n >= rank)
200181254a7Smrg 	    {
201181254a7Smrg 	      /* Break out of the loop.  */
202181254a7Smrg 	      continue_loop = 0;
203181254a7Smrg 	      break;
204181254a7Smrg 	    }
205181254a7Smrg 	  else
206181254a7Smrg 	    {
207181254a7Smrg 	      count[n]++;
208181254a7Smrg 	      base += sstride[n];
209181254a7Smrg 	      dest += dstride[n];
210181254a7Smrg 	    }
211181254a7Smrg 	}
212181254a7Smrg     }
213181254a7Smrg }
214181254a7Smrg 
215181254a7Smrg #endif
216