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