forked from llvm/llvm-project
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathfindloc.cpp
342 lines (321 loc) · 13.5 KB
/
findloc.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
//===-- runtime/findloc.cpp -----------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// Implements FINDLOC for all required operand types and shapes and result
// integer kinds.
#include "reduction-templates.h"
#include "flang/Common/long-double.h"
#include "flang/Runtime/character.h"
#include "flang/Runtime/reduction.h"
#include <cinttypes>
#include <complex>
namespace Fortran::runtime {
template <TypeCategory CAT1, int KIND1, TypeCategory CAT2, int KIND2>
struct Equality {
using Type1 = CppTypeFor<CAT1, KIND1>;
using Type2 = CppTypeFor<CAT2, KIND2>;
bool operator()(const Descriptor &array, const SubscriptValue at[],
const Descriptor &target) const {
return *array.Element<Type1>(at) == *target.OffsetElement<Type2>();
}
};
template <int KIND1, int KIND2>
struct Equality<TypeCategory::Complex, KIND1, TypeCategory::Complex, KIND2> {
using Type1 = CppTypeFor<TypeCategory::Complex, KIND1>;
using Type2 = CppTypeFor<TypeCategory::Complex, KIND2>;
bool operator()(const Descriptor &array, const SubscriptValue at[],
const Descriptor &target) const {
const Type1 &xz{*array.Element<Type1>(at)};
const Type2 &tz{*target.OffsetElement<Type2>()};
return xz.real() == tz.real() && xz.imag() == tz.imag();
}
};
template <int KIND1, TypeCategory CAT2, int KIND2>
struct Equality<TypeCategory::Complex, KIND1, CAT2, KIND2> {
using Type1 = CppTypeFor<TypeCategory::Complex, KIND1>;
using Type2 = CppTypeFor<CAT2, KIND2>;
bool operator()(const Descriptor &array, const SubscriptValue at[],
const Descriptor &target) const {
const Type1 &z{*array.Element<Type1>(at)};
return z.imag() == 0 && z.real() == *target.OffsetElement<Type2>();
}
};
template <TypeCategory CAT1, int KIND1, int KIND2>
struct Equality<CAT1, KIND1, TypeCategory::Complex, KIND2> {
using Type1 = CppTypeFor<CAT1, KIND1>;
using Type2 = CppTypeFor<TypeCategory::Complex, KIND2>;
bool operator()(const Descriptor &array, const SubscriptValue at[],
const Descriptor &target) const {
const Type2 &z{*target.OffsetElement<Type2>()};
return *array.Element<Type1>(at) == z.real() && z.imag() == 0;
}
};
template <int KIND> struct CharacterEquality {
using Type = CppTypeFor<TypeCategory::Character, KIND>;
bool operator()(const Descriptor &array, const SubscriptValue at[],
const Descriptor &target) const {
return CharacterScalarCompare<Type>(array.Element<Type>(at),
target.OffsetElement<Type>(),
array.ElementBytes() / static_cast<unsigned>(KIND),
target.ElementBytes() / static_cast<unsigned>(KIND)) == 0;
}
};
struct LogicalEquivalence {
bool operator()(const Descriptor &array, const SubscriptValue at[],
const Descriptor &target) const {
return IsLogicalElementTrue(array, at) ==
IsLogicalElementTrue(target, at /*ignored*/);
}
};
template <typename EQUALITY> class LocationAccumulator {
public:
LocationAccumulator(
const Descriptor &array, const Descriptor &target, bool back)
: array_{array}, target_{target}, back_{back} {
Reinitialize();
}
void Reinitialize() {
// per standard: result indices are all zero if no data
for (int j{0}; j < rank_; ++j) {
location_[j] = 0;
}
}
template <typename A> void GetResult(A *p, int zeroBasedDim = -1) {
if (zeroBasedDim >= 0) {
*p = location_[zeroBasedDim] -
array_.GetDimension(zeroBasedDim).LowerBound() + 1;
} else {
for (int j{0}; j < rank_; ++j) {
p[j] = location_[j] - array_.GetDimension(j).LowerBound() + 1;
}
}
}
template <typename IGNORED> bool AccumulateAt(const SubscriptValue at[]) {
if (equality_(array_, at, target_)) {
for (int j{0}; j < rank_; ++j) {
location_[j] = at[j];
}
return back_;
} else {
return true;
}
}
private:
const Descriptor &array_;
const Descriptor &target_;
const bool back_{false};
const int rank_{array_.rank()};
SubscriptValue location_[maxRank];
const EQUALITY equality_{};
};
template <TypeCategory XCAT, int XKIND, TypeCategory TARGET_CAT>
struct TotalNumericFindlocHelper {
template <int TARGET_KIND> struct Functor {
void operator()(Descriptor &result, const Descriptor &x,
const Descriptor &target, int kind, int dim, const Descriptor *mask,
bool back, Terminator &terminator) const {
using Eq = Equality<XCAT, XKIND, TARGET_CAT, TARGET_KIND>;
using Accumulator = LocationAccumulator<Eq>;
Accumulator accumulator{x, target, back};
DoTotalReduction<void>(x, dim, mask, accumulator, "FINDLOC", terminator);
ApplyIntegerKind<LocationResultHelper<Accumulator>::template Functor,
void>(kind, terminator, accumulator, result);
}
};
};
template <TypeCategory CAT,
template <TypeCategory XCAT, int XKIND, TypeCategory TARGET_CAT>
class HELPER>
struct NumericFindlocHelper {
template <int KIND> struct Functor {
void operator()(TypeCategory targetCat, int targetKind, Descriptor &result,
const Descriptor &x, const Descriptor &target, int kind, int dim,
const Descriptor *mask, bool back, Terminator &terminator) const {
switch (targetCat) {
case TypeCategory::Integer:
ApplyIntegerKind<
HELPER<CAT, KIND, TypeCategory::Integer>::template Functor, void>(
targetKind, terminator, result, x, target, kind, dim, mask, back,
terminator);
break;
case TypeCategory::Real:
ApplyFloatingPointKind<
HELPER<CAT, KIND, TypeCategory::Real>::template Functor, void>(
targetKind, terminator, result, x, target, kind, dim, mask, back,
terminator);
break;
case TypeCategory::Complex:
ApplyFloatingPointKind<
HELPER<CAT, KIND, TypeCategory::Complex>::template Functor, void>(
targetKind, terminator, result, x, target, kind, dim, mask, back,
terminator);
break;
default:
terminator.Crash(
"FINDLOC: bad target category %d for array category %d",
static_cast<int>(targetCat), static_cast<int>(CAT));
}
}
};
};
template <int KIND> struct CharacterFindlocHelper {
void operator()(Descriptor &result, const Descriptor &x,
const Descriptor &target, int kind, const Descriptor *mask, bool back,
Terminator &terminator) {
using Accumulator = LocationAccumulator<CharacterEquality<KIND>>;
Accumulator accumulator{x, target, back};
DoTotalReduction<void>(x, 0, mask, accumulator, "FINDLOC", terminator);
ApplyIntegerKind<LocationResultHelper<Accumulator>::template Functor, void>(
kind, terminator, accumulator, result);
}
};
static void LogicalFindlocHelper(Descriptor &result, const Descriptor &x,
const Descriptor &target, int kind, const Descriptor *mask, bool back,
Terminator &terminator) {
using Accumulator = LocationAccumulator<LogicalEquivalence>;
Accumulator accumulator{x, target, back};
DoTotalReduction<void>(x, 0, mask, accumulator, "FINDLOC", terminator);
ApplyIntegerKind<LocationResultHelper<Accumulator>::template Functor, void>(
kind, terminator, accumulator, result);
}
extern "C" {
void RTNAME(Findloc)(Descriptor &result, const Descriptor &x,
const Descriptor &target, int kind, const char *source, int line,
const Descriptor *mask, bool back) {
int rank{x.rank()};
SubscriptValue extent[1]{rank};
result.Establish(TypeCategory::Integer, kind, nullptr, 1, extent,
CFI_attribute_allocatable);
result.GetDimension(0).SetBounds(1, extent[0]);
Terminator terminator{source, line};
if (int stat{result.Allocate()}) {
terminator.Crash(
"FINDLOC: could not allocate memory for result; STAT=%d", stat);
}
CheckIntegerKind(terminator, kind, "FINDLOC");
auto xType{x.type().GetCategoryAndKind()};
auto targetType{target.type().GetCategoryAndKind()};
RUNTIME_CHECK(terminator, xType.has_value() && targetType.has_value());
switch (xType->first) {
case TypeCategory::Integer:
ApplyIntegerKind<NumericFindlocHelper<TypeCategory::Integer,
TotalNumericFindlocHelper>::template Functor,
void>(xType->second, terminator, targetType->first, targetType->second,
result, x, target, kind, 0, mask, back, terminator);
break;
case TypeCategory::Real:
ApplyFloatingPointKind<NumericFindlocHelper<TypeCategory::Real,
TotalNumericFindlocHelper>::template Functor,
void>(xType->second, terminator, targetType->first, targetType->second,
result, x, target, kind, 0, mask, back, terminator);
break;
case TypeCategory::Complex:
ApplyFloatingPointKind<NumericFindlocHelper<TypeCategory::Complex,
TotalNumericFindlocHelper>::template Functor,
void>(xType->second, terminator, targetType->first, targetType->second,
result, x, target, kind, 0, mask, back, terminator);
break;
case TypeCategory::Character:
RUNTIME_CHECK(terminator,
targetType->first == TypeCategory::Character &&
targetType->second == xType->second);
ApplyCharacterKind<CharacterFindlocHelper, void>(xType->second, terminator,
result, x, target, kind, mask, back, terminator);
break;
case TypeCategory::Logical:
RUNTIME_CHECK(terminator, targetType->first == TypeCategory::Logical);
LogicalFindlocHelper(result, x, target, kind, mask, back, terminator);
break;
default:
terminator.Crash(
"FINDLOC: Bad data type code (%d) for array", x.type().raw());
}
}
} // extern "C"
// FINDLOC with DIM=
template <TypeCategory XCAT, int XKIND, TypeCategory TARGET_CAT>
struct PartialNumericFindlocHelper {
template <int TARGET_KIND> struct Functor {
void operator()(Descriptor &result, const Descriptor &x,
const Descriptor &target, int kind, int dim, const Descriptor *mask,
bool back, Terminator &terminator) const {
using Eq = Equality<XCAT, XKIND, TARGET_CAT, TARGET_KIND>;
using Accumulator = LocationAccumulator<Eq>;
Accumulator accumulator{x, target, back};
ApplyIntegerKind<PartialLocationHelper<Accumulator>::template Functor,
void>(kind, terminator, result, x, dim, mask, terminator, "FINDLOC",
accumulator);
}
};
};
template <int KIND> struct PartialCharacterFindlocHelper {
void operator()(Descriptor &result, const Descriptor &x,
const Descriptor &target, int kind, int dim, const Descriptor *mask,
bool back, Terminator &terminator) {
using Accumulator = LocationAccumulator<CharacterEquality<KIND>>;
Accumulator accumulator{x, target, back};
ApplyIntegerKind<PartialLocationHelper<Accumulator>::template Functor,
void>(kind, terminator, result, x, dim, mask, terminator, "FINDLOC",
accumulator);
}
};
static void PartialLogicalFindlocHelper(Descriptor &result, const Descriptor &x,
const Descriptor &target, int kind, int dim, const Descriptor *mask,
bool back, Terminator &terminator) {
using Accumulator = LocationAccumulator<LogicalEquivalence>;
Accumulator accumulator{x, target, back};
ApplyIntegerKind<PartialLocationHelper<Accumulator>::template Functor, void>(
kind, terminator, result, x, dim, mask, terminator, "FINDLOC",
accumulator);
}
extern "C" {
void RTNAME(FindlocDim)(Descriptor &result, const Descriptor &x,
const Descriptor &target, int kind, int dim, const char *source, int line,
const Descriptor *mask, bool back) {
Terminator terminator{source, line};
CheckIntegerKind(terminator, kind, "FINDLOC");
auto xType{x.type().GetCategoryAndKind()};
auto targetType{target.type().GetCategoryAndKind()};
RUNTIME_CHECK(terminator, xType.has_value() && targetType.has_value());
switch (xType->first) {
case TypeCategory::Integer:
ApplyIntegerKind<NumericFindlocHelper<TypeCategory::Integer,
PartialNumericFindlocHelper>::template Functor,
void>(xType->second, terminator, targetType->first, targetType->second,
result, x, target, kind, dim, mask, back, terminator);
break;
case TypeCategory::Real:
ApplyFloatingPointKind<NumericFindlocHelper<TypeCategory::Real,
PartialNumericFindlocHelper>::template Functor,
void>(xType->second, terminator, targetType->first, targetType->second,
result, x, target, kind, dim, mask, back, terminator);
break;
case TypeCategory::Complex:
ApplyFloatingPointKind<NumericFindlocHelper<TypeCategory::Complex,
PartialNumericFindlocHelper>::template Functor,
void>(xType->second, terminator, targetType->first, targetType->second,
result, x, target, kind, dim, mask, back, terminator);
break;
case TypeCategory::Character:
RUNTIME_CHECK(terminator,
targetType->first == TypeCategory::Character &&
targetType->second == xType->second);
ApplyCharacterKind<PartialCharacterFindlocHelper, void>(xType->second,
terminator, result, x, target, kind, dim, mask, back, terminator);
break;
case TypeCategory::Logical:
RUNTIME_CHECK(terminator, targetType->first == TypeCategory::Logical);
PartialLogicalFindlocHelper(
result, x, target, kind, dim, mask, back, terminator);
break;
default:
terminator.Crash(
"FINDLOC: Bad data type code (%d) for array", x.type().raw());
}
}
} // extern "C"
} // namespace Fortran::runtime