1181254a7Smrg /* Implementation of the PARITY 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 #if defined (HAVE_GFC_LOGICAL_4) && defined (HAVE_GFC_LOGICAL_4)
30181254a7Smrg
31181254a7Smrg
32181254a7Smrg extern void parity_l4 (gfc_array_l4 * const restrict,
33181254a7Smrg gfc_array_l4 * const restrict, const index_type * const restrict);
34181254a7Smrg export_proto(parity_l4);
35181254a7Smrg
36181254a7Smrg void
parity_l4(gfc_array_l4 * const restrict retarray,gfc_array_l4 * const restrict array,const index_type * const restrict pdim)37181254a7Smrg parity_l4 (gfc_array_l4 * const restrict retarray,
38181254a7Smrg gfc_array_l4 * const restrict array,
39181254a7Smrg const index_type * const restrict pdim)
40181254a7Smrg {
41181254a7Smrg index_type count[GFC_MAX_DIMENSIONS];
42181254a7Smrg index_type extent[GFC_MAX_DIMENSIONS];
43181254a7Smrg index_type sstride[GFC_MAX_DIMENSIONS];
44181254a7Smrg index_type dstride[GFC_MAX_DIMENSIONS];
45181254a7Smrg const GFC_LOGICAL_4 * restrict base;
46181254a7Smrg GFC_LOGICAL_4 * restrict dest;
47181254a7Smrg index_type rank;
48181254a7Smrg index_type n;
49181254a7Smrg index_type len;
50181254a7Smrg index_type delta;
51181254a7Smrg index_type dim;
52181254a7Smrg int continue_loop;
53181254a7Smrg
54181254a7Smrg /* Make dim zero based to avoid confusion. */
55181254a7Smrg rank = GFC_DESCRIPTOR_RANK (array) - 1;
56181254a7Smrg dim = (*pdim) - 1;
57181254a7Smrg
58181254a7Smrg if (unlikely (dim < 0 || dim > rank))
59181254a7Smrg {
60181254a7Smrg runtime_error ("Dim argument incorrect in PARITY intrinsic: "
61181254a7Smrg "is %ld, should be between 1 and %ld",
62181254a7Smrg (long int) dim + 1, (long int) rank + 1);
63181254a7Smrg }
64181254a7Smrg
65181254a7Smrg len = GFC_DESCRIPTOR_EXTENT(array,dim);
66181254a7Smrg if (len < 0)
67181254a7Smrg len = 0;
68181254a7Smrg delta = GFC_DESCRIPTOR_STRIDE(array,dim);
69181254a7Smrg
70181254a7Smrg for (n = 0; n < dim; n++)
71181254a7Smrg {
72181254a7Smrg sstride[n] = GFC_DESCRIPTOR_STRIDE(array,n);
73181254a7Smrg extent[n] = GFC_DESCRIPTOR_EXTENT(array,n);
74181254a7Smrg
75181254a7Smrg if (extent[n] < 0)
76181254a7Smrg extent[n] = 0;
77181254a7Smrg }
78181254a7Smrg for (n = dim; n < rank; n++)
79181254a7Smrg {
80181254a7Smrg sstride[n] = GFC_DESCRIPTOR_STRIDE(array, n + 1);
81181254a7Smrg extent[n] = GFC_DESCRIPTOR_EXTENT(array, n + 1);
82181254a7Smrg
83181254a7Smrg if (extent[n] < 0)
84181254a7Smrg extent[n] = 0;
85181254a7Smrg }
86181254a7Smrg
87181254a7Smrg if (retarray->base_addr == NULL)
88181254a7Smrg {
89181254a7Smrg size_t alloc_size, str;
90181254a7Smrg
91181254a7Smrg for (n = 0; n < rank; n++)
92181254a7Smrg {
93181254a7Smrg if (n == 0)
94181254a7Smrg str = 1;
95181254a7Smrg else
96181254a7Smrg str = GFC_DESCRIPTOR_STRIDE(retarray,n-1) * extent[n-1];
97181254a7Smrg
98181254a7Smrg GFC_DIMENSION_SET(retarray->dim[n], 0, extent[n] - 1, str);
99181254a7Smrg
100181254a7Smrg }
101181254a7Smrg
102181254a7Smrg retarray->offset = 0;
103181254a7Smrg retarray->dtype.rank = rank;
104181254a7Smrg
105181254a7Smrg alloc_size = GFC_DESCRIPTOR_STRIDE(retarray,rank-1) * extent[rank-1];
106181254a7Smrg
107181254a7Smrg retarray->base_addr = xmallocarray (alloc_size, sizeof (GFC_LOGICAL_4));
108181254a7Smrg if (alloc_size == 0)
109181254a7Smrg {
110181254a7Smrg /* Make sure we have a zero-sized array. */
111181254a7Smrg GFC_DIMENSION_SET(retarray->dim[0], 0, -1, 1);
112181254a7Smrg return;
113181254a7Smrg
114181254a7Smrg }
115181254a7Smrg }
116181254a7Smrg else
117181254a7Smrg {
118181254a7Smrg if (rank != GFC_DESCRIPTOR_RANK (retarray))
119181254a7Smrg runtime_error ("rank of return array incorrect in"
120181254a7Smrg " PARITY intrinsic: is %ld, should be %ld",
121181254a7Smrg (long int) (GFC_DESCRIPTOR_RANK (retarray)),
122181254a7Smrg (long int) rank);
123181254a7Smrg
124181254a7Smrg if (unlikely (compile_options.bounds_check))
125181254a7Smrg bounds_ifunction_return ((array_t *) retarray, extent,
126181254a7Smrg "return value", "PARITY");
127181254a7Smrg }
128181254a7Smrg
129181254a7Smrg for (n = 0; n < rank; n++)
130181254a7Smrg {
131181254a7Smrg count[n] = 0;
132181254a7Smrg dstride[n] = GFC_DESCRIPTOR_STRIDE(retarray,n);
133181254a7Smrg if (extent[n] <= 0)
134181254a7Smrg return;
135181254a7Smrg }
136181254a7Smrg
137181254a7Smrg base = array->base_addr;
138181254a7Smrg dest = retarray->base_addr;
139181254a7Smrg
140181254a7Smrg continue_loop = 1;
141181254a7Smrg while (continue_loop)
142181254a7Smrg {
143181254a7Smrg const GFC_LOGICAL_4 * restrict src;
144181254a7Smrg GFC_LOGICAL_4 result;
145181254a7Smrg src = base;
146181254a7Smrg {
147181254a7Smrg
148181254a7Smrg result = 0;
149181254a7Smrg if (len <= 0)
150181254a7Smrg *dest = 0;
151181254a7Smrg else
152181254a7Smrg {
153181254a7Smrg #if ! defined HAVE_BACK_ARG
154181254a7Smrg for (n = 0; n < len; n++, src += delta)
155181254a7Smrg {
156181254a7Smrg #endif
157181254a7Smrg
158181254a7Smrg result = result != *src;
159181254a7Smrg }
160181254a7Smrg
161181254a7Smrg *dest = result;
162181254a7Smrg }
163181254a7Smrg }
164181254a7Smrg /* Advance to the next element. */
165181254a7Smrg count[0]++;
166181254a7Smrg base += sstride[0];
167181254a7Smrg dest += dstride[0];
168181254a7Smrg n = 0;
169181254a7Smrg while (count[n] == extent[n])
170181254a7Smrg {
171181254a7Smrg /* When we get to the end of a dimension, reset it and increment
172181254a7Smrg the next dimension. */
173181254a7Smrg count[n] = 0;
174181254a7Smrg /* We could precalculate these products, but this is a less
175181254a7Smrg frequently used path so probably not worth it. */
176181254a7Smrg base -= sstride[n] * extent[n];
177181254a7Smrg dest -= dstride[n] * extent[n];
178181254a7Smrg n++;
179181254a7Smrg if (n >= rank)
180181254a7Smrg {
181181254a7Smrg /* Break out of the loop. */
182181254a7Smrg continue_loop = 0;
183181254a7Smrg break;
184181254a7Smrg }
185181254a7Smrg else
186181254a7Smrg {
187181254a7Smrg count[n]++;
188181254a7Smrg base += sstride[n];
189181254a7Smrg dest += dstride[n];
190181254a7Smrg }
191181254a7Smrg }
192181254a7Smrg }
193181254a7Smrg }
194181254a7Smrg
195181254a7Smrg #endif
196