2021-12-06 19:57:32 +01:00
|
|
|
/* Implementation of the NORM2 intrinsic
|
2024-01-03 12:19:35 +01:00
|
|
|
Copyright (C) 2010-2024 Free Software Foundation, Inc.
|
2021-12-06 19:57:32 +01:00
|
|
|
Contributed by Tobias Burnus <burnus@net-b.de>
|
|
|
|
|
|
|
|
This file is part of the GNU Fortran runtime library (libgfortran).
|
|
|
|
|
|
|
|
Libgfortran is free software; you can redistribute it and/or
|
|
|
|
modify it under the terms of the GNU General Public
|
|
|
|
License as published by the Free Software Foundation; either
|
|
|
|
version 3 of the License, or (at your option) any later version.
|
|
|
|
|
|
|
|
Libgfortran is distributed in the hope that it will be useful,
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
GNU General Public License for more details.
|
|
|
|
|
|
|
|
Under Section 7 of GPL version 3, you are granted additional
|
|
|
|
permissions described in the GCC Runtime Library Exception, version
|
|
|
|
3.1, as published by the Free Software Foundation.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License and
|
|
|
|
a copy of the GCC Runtime Library Exception along with this program;
|
|
|
|
see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
|
|
|
|
<http://www.gnu.org/licenses/>. */
|
|
|
|
|
|
|
|
#include "libgfortran.h"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#if defined (HAVE_GFC_REAL_17) && defined (HAVE_GFC_REAL_17) && 1 /* FIXME: figure this out later. */ && 1 /* FIXME: figure this out later. */
|
|
|
|
|
|
|
|
#if defined(POWER_IEEE128)
|
|
|
|
#define MATHFUNC(funcname) __ ## funcname ## ieee128
|
fortran, libgfortran: Avoid using libquadmath for glibc 2.26+
As mentioned by Joseph in PR105101, glibc 2.26 or later has on x86
(both -m32/-m64), powerpc64le, ia64 and mips support for
*f128 math/complex APIs plus strtof128 and strfromf128, and these APIs allow
us to avoid libquadmath for Fortran purposes on these architectures,
replace *q math/complex APIs, strtof128 instead of strtoflt128 and,
while strfromf128 unfortunately isn't a perfect replacement to
quadmath_snprintf, it can be made to work.
The advantage of this is that when configured against such glibcs
(2.26 is now almost 5 years old), we can avoid linking against an extra shared
library and the math support in glibc is maintained better than libquadmath.
We need both a compiler change (so that for glibc 2.26+ it uses *f128 APIs
instead of *q) and library change.
The above mentioned problem with strfromf128 is that the strfrom* functions
are severely restricted versions of snprintf. In libgfortran, we handle
!isfinite differently and just use snprintf/quadmath_snprintf for
%+-#.*{L,Q}{f,e} printing.
strfrom* doesn't allow +, -, # modifiers and it only supports .34 or
similar precision, not .* . The L/Q etc. letters are omitted.
The + is there to force + sign at the start if it is positive.
Workaround in the patch is to add the + at the start manually for
!signbit (val).
The - (left alignment instead of right) I don't understand why we need it,
when minimum field width isn't specified (for strfrom* can't be specified),
no padding is ever added anywhere I believe.
The # is to force adding . - workaround is to search for first . or e or '\0'
character, if it is '\0', just append ., if it is e, insert . before e and
memmove the rest (which is just a few bytes, e, +/- and at most a few digits)
one byte later.
The .* case is handled by creating the format string for strfrom* by
snprintf into a temporary buffer.
As requested, this patch also switches from using __float128 type in
libgfortran to _Float128 which is equivalent on all arches that support
__float128.
The change is done in a backwards compatible change, when GCC is configured
against glibc 2.26 or newer, libgfortran.so.5 itself doesn't link against
-lquadmath nor uses any libquadmath APIs, libgfortran.a doesn't use any
libquadmath APIs either. User programs and libraries when being linked
by gfortran driver are linked against -lgfortran and -lquadmath, but
the latter only in the --as-needed linker mode, which means it needs
to be around during linking and will be linked in if there are any
calls to math/complex functions with real(kind=16) or complex(kind=16)
in compilation units compiled by older versions of gcc, but if either
user code doesn't call those math/complex functions for the largest
supported kind, or the code is recompiled by gcc with this change in,
libquadmath won't be linked in.
2022-06-28 Jakub Jelinek <jakub@redhat.com>
gcc/fortran/
* gfortran.h (gfc_real_info): Add use_iec_60559 bitfield.
* trans-types.h (gfc_real16_use_iec_60559): Declare.
* trans-types.cc (gfc_real16_use_iec_60559): Define.
(gfc_init_kinds): When building powerpc64le-linux libgfortran
on glibc 2.26 to 2.31, set gfc_real16_use_iec_60559 and
use_iec_60559.
(gfc_build_real_type): Set gfc_real16_use_iec_60559 and use_iec_60559
on glibc 2.26 or later.
* trans-intrinsic.cc (gfc_build_intrinsic_lib_fndecls): Adjust
comment. Handle gfc_real16_use_iec_60559.
(gfc_get_intrinsic_lib_fndecl): Handle use_iec_60559.
libgfortran/
* configure.ac: Check for strtof128 and strfromf128.
Check for math and complex *f128 functions. Set
have_iec_60559_libc_support to yes if *f128 support is around, for
--enable-libquadmath-support default to "default" rather than yes if
have_iec_60559_libc_support is yes.
* acinclude.m4 (LIBGFOR_CHECK_FLOAT128): Test
_Float128/_Complex _Float128 rather than __float128 and
_Complex float __attribute__((mode(TC))). If libquadmath support
is defaulted and have_iec_60559_libc_support is yes, define and subst
USE_IEC_60559. Remove unused LIBGFOR_BUILD_QUAD conditional.
* Makefile.am (kinds.h): Pass @USE_IEC_60559@ as an extra
mk-kinds-h.sh argument.
* mk-kinds-h.sh: Accept 4th use_iec_60559 argument. Use
_Float128/_Complex _Float128 types instead of __float128 and
_Complex float __attribute__((mode(TC))), and if use_iec_60559 is yes,
use f128 suffix instead of q and define GFC_REAL_16_USE_IEC_60559.
* kinds-override.h: Use _Float128/_Complex _Float128 types instead of
__float128 and _Complex float __attribute__((mode(TC))), if
USE_IEC_60559 is defined, use f128 suffixes instead of q and
define GFC_REAL_17_USE_IEC_60559.
* libgfortran.h: Don't include quadmath_weak.h if USE_IEC_60559 is
defined.
(GFC_REAL_16_INFINITY, GFC_REAL_16_QUIET_NAN): Define
for GFC_REAL_16_USE_IEC_60559 differently.
* caf/single.c (convert_type): Use _Float128/_Complex _Float128
instead of __float128 and _Complex float __attribute__((mode(TC))).
For HAVE_GFC_REAL_10 when HAVE_GFC_REAL_16 isn't defined use
_Complex long double instead of long double.
* ieee/issignaling_fallback.h (ieee854_float128_shape_type): Use
_Float128 instead of __float128.
(__issignalingf128): Change argument type to _Float128.
(issignaling): Use _Float128 instead of __float128 in _Generic.
* intrinsics/cshift0.c (cshift0): Use _Float128 instead of __float128
in a comment. Fix a comment typo, logn double -> long double.
* intrinsics/erfc_scaled.c (_THRESH, _M_2_SQRTPI, _INF, _ERFC, _EXP):
Use different definitions if GFC_REAL_16_USE_IEC_60559.
(_THRESH, _M_2_SQRTPI): Use GFC_REAL_17_LITERAL macro.
(_ERFC, _EXP): Use different definitions if GFC_REAL_17_USE_IEC_60559.
* intrinsics/spread_generic.c (spread, spread_scalar): Use _Float128
instead of __float128 in a comment. Fix a comment typo,
logn double -> long double.
* intrinsics/trigd.c (ENABLE_SIND, ENABLE_COSD, ENABLE_TAND): Handle
GFC_REAL_16_USE_IEC_60559.
* intrinsics/pack_generic.c (pack): Use _Float128 instead of
__float128 in a comment. Fix a comment typo, logn double ->
long double.
* intrinsics/unpack_generic.c (unpack1, unpack0): Likewise.
* runtime/in_pack_generic.c (internal_pack): Likewise.
* runtime/in_unpack_generic.c (internal_unpack): Likewise.
* io/read.c (convert_real, convert_infnan): Handle
GFC_REAL_16_USE_IEC_60559 and GFC_REAL_17_USE_IEC_60559.
* io/transfer128.c (tmp1, tmp2): Don't define if libquadmath
isn't needed.
* io/write_float.def (gfor_strfromf128): New function.
(DTOA2Q, FDTOA2Q): Define differently if
GFC_REAL_16_USE_IEC_60559 or GFC_REAL_17_USE_IEC_60559.
* m4/mtype.m4: Use different suffix if GFC_REAL_16_USE_IEC_60559
or GFC_REAL_17_USE_IEC_60559.
* config.h.in: Regenerated.
* configure: Regenerated.
* Makefile.in: Regenerated.
* generated/bessel_r16.c: Regenerated.
* generated/bessel_r17.c: Regenerated.
* generated/norm2_r16.c: Regenerated.
* generated/norm2_r17.c: Regenerated.
2022-06-28 13:05:28 +02:00
|
|
|
#elif defined(GFC_REAL_17_USE_IEC_60559)
|
|
|
|
#define MATHFUNC(funcname) funcname ## f128
|
2021-12-06 19:57:32 +01:00
|
|
|
#else
|
|
|
|
#define MATHFUNC(funcname) funcname ## q
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
extern void norm2_r17 (gfc_array_r17 * const restrict,
|
|
|
|
gfc_array_r17 * const restrict, const index_type * const restrict);
|
|
|
|
export_proto(norm2_r17);
|
|
|
|
|
|
|
|
void
|
|
|
|
norm2_r17 (gfc_array_r17 * const restrict retarray,
|
|
|
|
gfc_array_r17 * const restrict array,
|
|
|
|
const index_type * const restrict pdim)
|
|
|
|
{
|
|
|
|
index_type count[GFC_MAX_DIMENSIONS];
|
|
|
|
index_type extent[GFC_MAX_DIMENSIONS];
|
|
|
|
index_type sstride[GFC_MAX_DIMENSIONS];
|
|
|
|
index_type dstride[GFC_MAX_DIMENSIONS];
|
|
|
|
const GFC_REAL_17 * restrict base;
|
|
|
|
GFC_REAL_17 * restrict dest;
|
|
|
|
index_type rank;
|
|
|
|
index_type n;
|
|
|
|
index_type len;
|
|
|
|
index_type delta;
|
|
|
|
index_type dim;
|
|
|
|
int continue_loop;
|
|
|
|
|
|
|
|
/* Make dim zero based to avoid confusion. */
|
|
|
|
rank = GFC_DESCRIPTOR_RANK (array) - 1;
|
|
|
|
dim = (*pdim) - 1;
|
|
|
|
|
|
|
|
if (unlikely (dim < 0 || dim > rank))
|
|
|
|
{
|
|
|
|
runtime_error ("Dim argument incorrect in NORM intrinsic: "
|
|
|
|
"is %ld, should be between 1 and %ld",
|
|
|
|
(long int) dim + 1, (long int) rank + 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
len = GFC_DESCRIPTOR_EXTENT(array,dim);
|
|
|
|
if (len < 0)
|
|
|
|
len = 0;
|
|
|
|
delta = GFC_DESCRIPTOR_STRIDE(array,dim);
|
|
|
|
|
|
|
|
for (n = 0; n < dim; n++)
|
|
|
|
{
|
|
|
|
sstride[n] = GFC_DESCRIPTOR_STRIDE(array,n);
|
|
|
|
extent[n] = GFC_DESCRIPTOR_EXTENT(array,n);
|
|
|
|
|
|
|
|
if (extent[n] < 0)
|
|
|
|
extent[n] = 0;
|
|
|
|
}
|
|
|
|
for (n = dim; n < rank; n++)
|
|
|
|
{
|
|
|
|
sstride[n] = GFC_DESCRIPTOR_STRIDE(array, n + 1);
|
|
|
|
extent[n] = GFC_DESCRIPTOR_EXTENT(array, n + 1);
|
|
|
|
|
|
|
|
if (extent[n] < 0)
|
|
|
|
extent[n] = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (retarray->base_addr == NULL)
|
|
|
|
{
|
|
|
|
size_t alloc_size, str;
|
|
|
|
|
|
|
|
for (n = 0; n < rank; n++)
|
|
|
|
{
|
|
|
|
if (n == 0)
|
|
|
|
str = 1;
|
|
|
|
else
|
|
|
|
str = GFC_DESCRIPTOR_STRIDE(retarray,n-1) * extent[n-1];
|
|
|
|
|
|
|
|
GFC_DIMENSION_SET(retarray->dim[n], 0, extent[n] - 1, str);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
retarray->offset = 0;
|
|
|
|
retarray->dtype.rank = rank;
|
|
|
|
|
|
|
|
alloc_size = GFC_DESCRIPTOR_STRIDE(retarray,rank-1) * extent[rank-1];
|
|
|
|
|
|
|
|
retarray->base_addr = xmallocarray (alloc_size, sizeof (GFC_REAL_17));
|
|
|
|
if (alloc_size == 0)
|
libgfortran: Remove empty array descriptor first dimension overwrite [PR112371]
Remove the forced overwrite of the first dimension of the result array
descriptor to set it to zero extent, in the function templates for
transformational functions doing an array reduction along a dimension. This
overwrite, which happened before early returning in case the result array
was empty, was wrong because an array may have a non-zero extent in the
first dimension and still be empty if it has a zero extent in a higher
dimension. Overwriting the dimension was resulting in wrong array result
upper bound for the first dimension in that case.
The offending piece of code was present in several places, and this removes
them all. More precisely, there is only one case to fix for logical
reduction functions, and there are three cases for other reduction
functions, corresponding to non-masked reduction, reduction with array mask,
and reduction with scalar mask. The impacted m4 files are
ifunction_logical.m4 for logical reduction functions, ifunction.m4 for
regular functions and types, ifunction-s.m4 for character minloc and maxloc,
ifunction-s2.m4 for character minval and maxval, and ifindloc1.m4 for
findloc.
PR fortran/112371
libgfortran/ChangeLog:
* m4/ifunction.m4 (START_ARRAY_FUNCTION, START_MASKED_ARRAY_FUNCTION,
SCALAR_ARRAY_FUNCTION): Remove overwrite of the first dimension of the
array descriptor.
* m4/ifunction-s.m4 (START_ARRAY_FUNCTION, START_MASKED_ARRAY_FUNCTION,
SCALAR_ARRAY_FUNCTION): Ditto.
* m4/ifunction-s2.m4 (START_ARRAY_FUNCTION,
START_MASKED_ARRAY_FUNCTION, SCALAR_ARRAY_FUNCTION): Ditto.
* m4/ifunction_logical.m4 (START_ARRAY_FUNCTION): Ditto.
* m4/ifindloc1.m4: Ditto.
* generated/all_l1.c: Regenerate.
* generated/all_l16.c: Regenerate.
* generated/all_l2.c: Regenerate.
* generated/all_l4.c: Regenerate.
* generated/all_l8.c: Regenerate.
* generated/any_l1.c: Regenerate.
* generated/any_l16.c: Regenerate.
* generated/any_l2.c: Regenerate.
* generated/any_l4.c: Regenerate.
* generated/any_l8.c: Regenerate.
* generated/count_16_l.c: Regenerate.
* generated/count_1_l.c: Regenerate.
* generated/count_2_l.c: Regenerate.
* generated/count_4_l.c: Regenerate.
* generated/count_8_l.c: Regenerate.
* generated/findloc1_c10.c: Regenerate.
* generated/findloc1_c16.c: Regenerate.
* generated/findloc1_c17.c: Regenerate.
* generated/findloc1_c4.c: Regenerate.
* generated/findloc1_c8.c: Regenerate.
* generated/findloc1_i1.c: Regenerate.
* generated/findloc1_i16.c: Regenerate.
* generated/findloc1_i2.c: Regenerate.
* generated/findloc1_i4.c: Regenerate.
* generated/findloc1_i8.c: Regenerate.
* generated/findloc1_r10.c: Regenerate.
* generated/findloc1_r16.c: Regenerate.
* generated/findloc1_r17.c: Regenerate.
* generated/findloc1_r4.c: Regenerate.
* generated/findloc1_r8.c: Regenerate.
* generated/findloc1_s1.c: Regenerate.
* generated/findloc1_s4.c: Regenerate.
* generated/iall_i1.c: Regenerate.
* generated/iall_i16.c: Regenerate.
* generated/iall_i2.c: Regenerate.
* generated/iall_i4.c: Regenerate.
* generated/iall_i8.c: Regenerate.
* generated/iany_i1.c: Regenerate.
* generated/iany_i16.c: Regenerate.
* generated/iany_i2.c: Regenerate.
* generated/iany_i4.c: Regenerate.
* generated/iany_i8.c: Regenerate.
* generated/iparity_i1.c: Regenerate.
* generated/iparity_i16.c: Regenerate.
* generated/iparity_i2.c: Regenerate.
* generated/iparity_i4.c: Regenerate.
* generated/iparity_i8.c: Regenerate.
* generated/maxloc1_16_i1.c: Regenerate.
* generated/maxloc1_16_i16.c: Regenerate.
* generated/maxloc1_16_i2.c: Regenerate.
* generated/maxloc1_16_i4.c: Regenerate.
* generated/maxloc1_16_i8.c: Regenerate.
* generated/maxloc1_16_r10.c: Regenerate.
* generated/maxloc1_16_r16.c: Regenerate.
* generated/maxloc1_16_r17.c: Regenerate.
* generated/maxloc1_16_r4.c: Regenerate.
* generated/maxloc1_16_r8.c: Regenerate.
* generated/maxloc1_16_s1.c: Regenerate.
* generated/maxloc1_16_s4.c: Regenerate.
* generated/maxloc1_4_i1.c: Regenerate.
* generated/maxloc1_4_i16.c: Regenerate.
* generated/maxloc1_4_i2.c: Regenerate.
* generated/maxloc1_4_i4.c: Regenerate.
* generated/maxloc1_4_i8.c: Regenerate.
* generated/maxloc1_4_r10.c: Regenerate.
* generated/maxloc1_4_r16.c: Regenerate.
* generated/maxloc1_4_r17.c: Regenerate.
* generated/maxloc1_4_r4.c: Regenerate.
* generated/maxloc1_4_r8.c: Regenerate.
* generated/maxloc1_4_s1.c: Regenerate.
* generated/maxloc1_4_s4.c: Regenerate.
* generated/maxloc1_8_i1.c: Regenerate.
* generated/maxloc1_8_i16.c: Regenerate.
* generated/maxloc1_8_i2.c: Regenerate.
* generated/maxloc1_8_i4.c: Regenerate.
* generated/maxloc1_8_i8.c: Regenerate.
* generated/maxloc1_8_r10.c: Regenerate.
* generated/maxloc1_8_r16.c: Regenerate.
* generated/maxloc1_8_r17.c: Regenerate.
* generated/maxloc1_8_r4.c: Regenerate.
* generated/maxloc1_8_r8.c: Regenerate.
* generated/maxloc1_8_s1.c: Regenerate.
* generated/maxloc1_8_s4.c: Regenerate.
* generated/maxval1_s1.c: Regenerate.
* generated/maxval1_s4.c: Regenerate.
* generated/maxval_i1.c: Regenerate.
* generated/maxval_i16.c: Regenerate.
* generated/maxval_i2.c: Regenerate.
* generated/maxval_i4.c: Regenerate.
* generated/maxval_i8.c: Regenerate.
* generated/maxval_r10.c: Regenerate.
* generated/maxval_r16.c: Regenerate.
* generated/maxval_r17.c: Regenerate.
* generated/maxval_r4.c: Regenerate.
* generated/maxval_r8.c: Regenerate.
* generated/minloc1_16_i1.c: Regenerate.
* generated/minloc1_16_i16.c: Regenerate.
* generated/minloc1_16_i2.c: Regenerate.
* generated/minloc1_16_i4.c: Regenerate.
* generated/minloc1_16_i8.c: Regenerate.
* generated/minloc1_16_r10.c: Regenerate.
* generated/minloc1_16_r16.c: Regenerate.
* generated/minloc1_16_r17.c: Regenerate.
* generated/minloc1_16_r4.c: Regenerate.
* generated/minloc1_16_r8.c: Regenerate.
* generated/minloc1_16_s1.c: Regenerate.
* generated/minloc1_16_s4.c: Regenerate.
* generated/minloc1_4_i1.c: Regenerate.
* generated/minloc1_4_i16.c: Regenerate.
* generated/minloc1_4_i2.c: Regenerate.
* generated/minloc1_4_i4.c: Regenerate.
* generated/minloc1_4_i8.c: Regenerate.
* generated/minloc1_4_r10.c: Regenerate.
* generated/minloc1_4_r16.c: Regenerate.
* generated/minloc1_4_r17.c: Regenerate.
* generated/minloc1_4_r4.c: Regenerate.
* generated/minloc1_4_r8.c: Regenerate.
* generated/minloc1_4_s1.c: Regenerate.
* generated/minloc1_4_s4.c: Regenerate.
* generated/minloc1_8_i1.c: Regenerate.
* generated/minloc1_8_i16.c: Regenerate.
* generated/minloc1_8_i2.c: Regenerate.
* generated/minloc1_8_i4.c: Regenerate.
* generated/minloc1_8_i8.c: Regenerate.
* generated/minloc1_8_r10.c: Regenerate.
* generated/minloc1_8_r16.c: Regenerate.
* generated/minloc1_8_r17.c: Regenerate.
* generated/minloc1_8_r4.c: Regenerate.
* generated/minloc1_8_r8.c: Regenerate.
* generated/minloc1_8_s1.c: Regenerate.
* generated/minloc1_8_s4.c: Regenerate.
* generated/minval1_s1.c: Regenerate.
* generated/minval1_s4.c: Regenerate.
* generated/minval_i1.c: Regenerate.
* generated/minval_i16.c: Regenerate.
* generated/minval_i2.c: Regenerate.
* generated/minval_i4.c: Regenerate.
* generated/minval_i8.c: Regenerate.
* generated/minval_r10.c: Regenerate.
* generated/minval_r16.c: Regenerate.
* generated/minval_r17.c: Regenerate.
* generated/minval_r4.c: Regenerate.
* generated/minval_r8.c: Regenerate.
* generated/norm2_r10.c: Regenerate.
* generated/norm2_r16.c: Regenerate.
* generated/norm2_r17.c: Regenerate.
* generated/norm2_r4.c: Regenerate.
* generated/norm2_r8.c: Regenerate.
* generated/parity_l1.c: Regenerate.
* generated/parity_l16.c: Regenerate.
* generated/parity_l2.c: Regenerate.
* generated/parity_l4.c: Regenerate.
* generated/parity_l8.c: Regenerate.
* generated/product_c10.c: Regenerate.
* generated/product_c16.c: Regenerate.
* generated/product_c17.c: Regenerate.
* generated/product_c4.c: Regenerate.
* generated/product_c8.c: Regenerate.
* generated/product_i1.c: Regenerate.
* generated/product_i16.c: Regenerate.
* generated/product_i2.c: Regenerate.
* generated/product_i4.c: Regenerate.
* generated/product_i8.c: Regenerate.
* generated/product_r10.c: Regenerate.
* generated/product_r16.c: Regenerate.
* generated/product_r17.c: Regenerate.
* generated/product_r4.c: Regenerate.
* generated/product_r8.c: Regenerate.
* generated/sum_c10.c: Regenerate.
* generated/sum_c16.c: Regenerate.
* generated/sum_c17.c: Regenerate.
* generated/sum_c4.c: Regenerate.
* generated/sum_c8.c: Regenerate.
* generated/sum_i1.c: Regenerate.
* generated/sum_i16.c: Regenerate.
* generated/sum_i2.c: Regenerate.
* generated/sum_i4.c: Regenerate.
* generated/sum_i8.c: Regenerate.
* generated/sum_r10.c: Regenerate.
* generated/sum_r16.c: Regenerate.
* generated/sum_r17.c: Regenerate.
* generated/sum_r4.c: Regenerate.
* generated/sum_r8.c: Regenerate.
gcc/testsuite/ChangeLog:
* gfortran.dg/bound_11.f90: New test.
2023-11-07 11:24:04 +01:00
|
|
|
return;
|
2021-12-06 19:57:32 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (rank != GFC_DESCRIPTOR_RANK (retarray))
|
|
|
|
runtime_error ("rank of return array incorrect in"
|
|
|
|
" NORM intrinsic: is %ld, should be %ld",
|
|
|
|
(long int) (GFC_DESCRIPTOR_RANK (retarray)),
|
|
|
|
(long int) rank);
|
|
|
|
|
|
|
|
if (unlikely (compile_options.bounds_check))
|
|
|
|
bounds_ifunction_return ((array_t *) retarray, extent,
|
|
|
|
"return value", "NORM");
|
|
|
|
}
|
|
|
|
|
|
|
|
for (n = 0; n < rank; n++)
|
|
|
|
{
|
|
|
|
count[n] = 0;
|
|
|
|
dstride[n] = GFC_DESCRIPTOR_STRIDE(retarray,n);
|
|
|
|
if (extent[n] <= 0)
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
base = array->base_addr;
|
|
|
|
dest = retarray->base_addr;
|
|
|
|
|
|
|
|
continue_loop = 1;
|
|
|
|
while (continue_loop)
|
|
|
|
{
|
|
|
|
const GFC_REAL_17 * restrict src;
|
|
|
|
GFC_REAL_17 result;
|
|
|
|
src = base;
|
|
|
|
{
|
|
|
|
|
|
|
|
GFC_REAL_17 scale;
|
|
|
|
result = 0;
|
|
|
|
scale = 1;
|
|
|
|
if (len <= 0)
|
|
|
|
*dest = 0;
|
|
|
|
else
|
|
|
|
{
|
|
|
|
#if ! defined HAVE_BACK_ARG
|
|
|
|
for (n = 0; n < len; n++, src += delta)
|
|
|
|
{
|
|
|
|
#endif
|
|
|
|
|
|
|
|
if (*src != 0)
|
|
|
|
{
|
|
|
|
GFC_REAL_17 absX, val;
|
|
|
|
absX = MATHFUNC(fabs) (*src);
|
|
|
|
if (scale < absX)
|
|
|
|
{
|
|
|
|
val = scale / absX;
|
|
|
|
result = 1 + result * val * val;
|
|
|
|
scale = absX;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
val = absX / scale;
|
|
|
|
result += val * val;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
result = scale * MATHFUNC(sqrt) (result);
|
|
|
|
*dest = result;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/* Advance to the next element. */
|
|
|
|
count[0]++;
|
|
|
|
base += sstride[0];
|
|
|
|
dest += dstride[0];
|
|
|
|
n = 0;
|
|
|
|
while (count[n] == extent[n])
|
|
|
|
{
|
|
|
|
/* When we get to the end of a dimension, reset it and increment
|
|
|
|
the next dimension. */
|
|
|
|
count[n] = 0;
|
|
|
|
/* We could precalculate these products, but this is a less
|
|
|
|
frequently used path so probably not worth it. */
|
|
|
|
base -= sstride[n] * extent[n];
|
|
|
|
dest -= dstride[n] * extent[n];
|
|
|
|
n++;
|
|
|
|
if (n >= rank)
|
|
|
|
{
|
|
|
|
/* Break out of the loop. */
|
|
|
|
continue_loop = 0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
count[n]++;
|
|
|
|
base += sstride[n];
|
|
|
|
dest += dstride[n];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif
|