@@ -182,14 +182,8 @@ static Expr<T> FoldCount(FoldingContext &context, FunctionRef<T> &&ref) {
182
182
if (const Constant<LogicalResult> *mask{arg.empty ()
183
183
? nullptr
184
184
: Folder<LogicalResult>{context}.Folding (arg[0 ])}) {
185
- std::optional<ConstantSubscript> dim;
186
- if (arg.size () > 1 && arg[1 ]) {
187
- dim = CheckDIM (context, arg[1 ], mask->Rank ());
188
- if (!dim) {
189
- mask = nullptr ;
190
- }
191
- }
192
- if (mask) {
185
+ std::optional<int > dim;
186
+ if (CheckReductionDIM (dim, context, arg, 1 , mask->Rank ())) {
193
187
auto accumulator{[&](Scalar<T> &element, const ConstantSubscripts &at) {
194
188
if (mask->At (at).IsTrue ()) {
195
189
element = element.AddSigned (Scalar<T>{1 }).value ;
@@ -201,13 +195,159 @@ static Expr<T> FoldCount(FoldingContext &context, FunctionRef<T> &&ref) {
201
195
return Expr<T>{std::move (ref)};
202
196
}
203
197
198
+ // FINDLOC()
199
+ class FindlocHelper {
200
+ public:
201
+ FindlocHelper (
202
+ DynamicType &&type, ActualArguments &arg, FoldingContext &context)
203
+ : type_{type}, arg_{arg}, context_{context} {}
204
+ using Result = std::optional<Constant<SubscriptInteger>>;
205
+ using Types = AllIntrinsicTypes;
206
+
207
+ template <typename T> Result Test () const {
208
+ if (T::category != type_.category () || T::kind != type_.kind ()) {
209
+ return std::nullopt;
210
+ }
211
+ CHECK (arg_.size () == 6 );
212
+ Folder<T> folder{context_};
213
+ Constant<T> *array{folder.Folding (arg_[0 ])};
214
+ Constant<T> *value{folder.Folding (arg_[1 ])};
215
+ if (!array || !value) {
216
+ return std::nullopt;
217
+ }
218
+ std::optional<int > dim;
219
+ Constant<LogicalResult> *mask{
220
+ GetReductionMASK (arg_[3 ], array->shape (), context_)};
221
+ if ((!mask && arg_[3 ]) ||
222
+ !CheckReductionDIM (dim, context_, arg_, 2 , array->Rank ())) {
223
+ return std::nullopt;
224
+ }
225
+ bool back{false };
226
+ if (arg_[5 ]) {
227
+ const auto *backConst{Folder<LogicalResult>{context_}.Folding (arg_[5 ])};
228
+ if (backConst) {
229
+ back = backConst->GetScalarValue ().value ().IsTrue ();
230
+ } else {
231
+ return std::nullopt;
232
+ }
233
+ }
234
+ // Use lower bounds of 1 exclusively.
235
+ array->SetLowerBoundsToOne ();
236
+ ConstantSubscripts at{array->lbounds ()}, maskAt, resultIndices, resultShape;
237
+ if (mask) {
238
+ mask->SetLowerBoundsToOne ();
239
+ maskAt = mask->lbounds ();
240
+ }
241
+ if (dim) { // DIM=
242
+ if (*dim < 1 || *dim > array->Rank ()) {
243
+ context_.messages ().Say (
244
+ " FINDLOC(DIM=%d) is out of range" _err_en_US, *dim);
245
+ return std::nullopt;
246
+ }
247
+ int zbDim{*dim - 1 };
248
+ resultShape = array->shape ();
249
+ resultShape.erase (
250
+ resultShape.begin () + zbDim); // scalar if array is vector
251
+ ConstantSubscript dimLength{array->shape ()[zbDim]};
252
+ ConstantSubscript n{GetSize (resultShape)};
253
+ for (ConstantSubscript j{0 }; j < n; ++j) {
254
+ ConstantSubscript hit{array->lbounds ()[zbDim] - 1 };
255
+ for (ConstantSubscript k{0 }; k < dimLength;
256
+ ++k, ++at[zbDim], mask && ++maskAt[zbDim]) {
257
+ if ((!mask || mask->At (maskAt).IsTrue ()) &&
258
+ IsHit (array->At (at), *value)) {
259
+ hit = at[zbDim];
260
+ if (!back) {
261
+ break ;
262
+ }
263
+ }
264
+ }
265
+ resultIndices.emplace_back (hit);
266
+ at[zbDim] = array->lbounds ()[zbDim] + dimLength - 1 ;
267
+ array->IncrementSubscripts (at);
268
+ at[zbDim] = array->lbounds ()[zbDim];
269
+ if (mask) {
270
+ maskAt[zbDim] = mask->lbounds ()[zbDim] + dimLength - 1 ;
271
+ mask->IncrementSubscripts (maskAt);
272
+ maskAt[zbDim] = mask->lbounds ()[zbDim];
273
+ }
274
+ }
275
+ } else { // no DIM=
276
+ resultShape = ConstantSubscripts{array->Rank ()}; // always a vector
277
+ ConstantSubscript n{GetSize (array->shape ())};
278
+ resultIndices = ConstantSubscripts (array->Rank (), 0 );
279
+ for (ConstantSubscript j{0 }; j < n; ++j, array->IncrementSubscripts (at),
280
+ mask && mask->IncrementSubscripts (maskAt)) {
281
+ if ((!mask || mask->At (maskAt).IsTrue ()) &&
282
+ IsHit (array->At (at), *value)) {
283
+ resultIndices = at;
284
+ if (!back) {
285
+ break ;
286
+ }
287
+ }
288
+ }
289
+ }
290
+ std::vector<Scalar<SubscriptInteger>> resultElements;
291
+ for (ConstantSubscript j : resultIndices) {
292
+ resultElements.emplace_back (j);
293
+ }
294
+ return Constant<SubscriptInteger>{
295
+ std::move (resultElements), std::move (resultShape)};
296
+ }
297
+
298
+ private:
299
+ template <typename T>
300
+ bool IsHit (typename Constant<T>::Element element, Constant<T> value) const {
301
+ std::optional<Expr<LogicalResult>> cmp;
302
+ if constexpr (T::category == TypeCategory::Logical) {
303
+ // array(at) .EQV. value?
304
+ cmp.emplace (
305
+ ConvertToType<LogicalResult>(Expr<T>{LogicalOperation<T::kind>{
306
+ LogicalOperator::Eqv, Expr<T>{Constant<T>{std::move (element)}},
307
+ Expr<T>{std::move (value)}}}));
308
+ } else { // array(at) .EQ. value?
309
+ cmp.emplace (PackageRelation (RelationalOperator::EQ,
310
+ Expr<T>{Constant<T>{std::move (element)}}, Expr<T>{std::move (value)}));
311
+ }
312
+ Expr<LogicalResult> folded{Fold (context_, std::move (*cmp))};
313
+ return GetScalarConstantValue<LogicalResult>(folded).value ().IsTrue ();
314
+ }
315
+
316
+ DynamicType type_;
317
+ ActualArguments &arg_;
318
+ FoldingContext &context_;
319
+ };
320
+
321
+ static std::optional<Constant<SubscriptInteger>> FoldFindlocCall (
322
+ ActualArguments &arg, FoldingContext &context) {
323
+ CHECK (arg.size () == 6 );
324
+ if (arg[0 ]) {
325
+ if (auto type{arg[0 ]->GetType ()}) {
326
+ return common::SearchTypes (FindlocHelper{std::move (*type), arg, context});
327
+ }
328
+ }
329
+ return std::nullopt;
330
+ }
331
+
332
+ template <typename T>
333
+ static Expr<T> FoldFindloc (FoldingContext &context, FunctionRef<T> &&ref) {
334
+ static_assert (T::category == TypeCategory::Integer);
335
+ if (std::optional<Constant<SubscriptInteger>> found{
336
+ FoldFindlocCall (ref.arguments (), context)}) {
337
+ return Expr<T>{Fold (
338
+ context, ConvertToType<T>(Expr<SubscriptInteger>{std::move (*found)}))};
339
+ } else {
340
+ return Expr<T>{std::move (ref)};
341
+ }
342
+ }
343
+
204
344
// for IALL, IANY, & IPARITY
205
345
template <typename T>
206
346
static Expr<T> FoldBitReduction (FoldingContext &context, FunctionRef<T> &&ref,
207
347
Scalar<T> (Scalar<T>::*operation)(const Scalar<T> &) const ,
208
348
Scalar<T> identity) {
209
349
static_assert (T::category == TypeCategory::Integer);
210
- std::optional<ConstantSubscript > dim;
350
+ std::optional<int > dim;
211
351
if (std::optional<Constant<T>> array{
212
352
ProcessReductionArgs<T>(context, ref.arguments (), dim, identity,
213
353
/* ARRAY=*/ 0 , /* DIM=*/ 1 , /* MASK=*/ 2 )}) {
@@ -310,6 +450,8 @@ Expr<Type<TypeCategory::Integer, KIND>> FoldIntrinsicFunction(
310
450
} else {
311
451
DIE (" exponent argument must be real" );
312
452
}
453
+ } else if (name == " findloc" ) {
454
+ return FoldFindloc<T>(context, std::move (funcRef));
313
455
} else if (name == " huge" ) {
314
456
return Expr<T>{Scalar<T>::HUGE ()};
315
457
} else if (name == " iachar" || name == " ichar" ) {
@@ -711,7 +853,7 @@ Expr<Type<TypeCategory::Integer, KIND>> FoldIntrinsicFunction(
711
853
} else if (name == " ubound" ) {
712
854
return UBOUND (context, std::move (funcRef));
713
855
}
714
- // TODO: dot_product, findloc, ibits, image_status, ishftc,
856
+ // TODO: dot_product, ibits, image_status, ishftc,
715
857
// matmul, maxloc, minloc, sign, transfer
716
858
return Expr<T>{std::move (funcRef)};
717
859
}
0 commit comments