//===-- lib/runtime/findloc.h -----------------------------------*- C++ -*-===// // // 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. #ifndef FLANG_RT_RUNTIME_FINDLOC_H_ #define FLANG_RT_RUNTIME_FINDLOC_H_ #include "flang-rt/runtime/reduction-templates.h" #include "flang/Runtime/character.h" #include "flang/Runtime/reduction.h" #include #include namespace Fortran::runtime { template struct Equality { using Type1 = CppTypeFor; using Type2 = CppTypeFor; RT_API_ATTRS bool operator()(const Descriptor &array, const SubscriptValue at[], const Descriptor &target) const { if constexpr (KIND1 >= KIND2) { return *array.Element(at) == static_cast(*target.OffsetElement()); } else { return static_cast(*array.Element(at)) == *target.OffsetElement(); } } }; template struct Equality { using Type1 = CppTypeFor; using Type2 = CppTypeFor; RT_API_ATTRS bool operator()(const Descriptor &array, const SubscriptValue at[], const Descriptor &target) const { const Type1 &xz{*array.Element(at)}; const Type2 &tz{*target.OffsetElement()}; return xz.real() == tz.real() && xz.imag() == tz.imag(); } }; template struct Equality { using Type1 = CppTypeFor; using Type2 = CppTypeFor; RT_API_ATTRS bool operator()(const Descriptor &array, const SubscriptValue at[], const Descriptor &target) const { const Type1 &z{*array.Element(at)}; return z.imag() == 0 && z.real() == *target.OffsetElement(); } }; template struct Equality { using Type1 = CppTypeFor; using Type2 = CppTypeFor; RT_API_ATTRS bool operator()(const Descriptor &array, const SubscriptValue at[], const Descriptor &target) const { const Type2 &z{*target.OffsetElement()}; return *array.Element(at) == z.real() && z.imag() == 0; } }; template struct CharacterEquality { using Type = CppTypeFor; RT_API_ATTRS bool operator()(const Descriptor &array, const SubscriptValue at[], const Descriptor &target) const { return CharacterScalarCompare(array.Element(at), target.OffsetElement(), array.ElementBytes() / static_cast(KIND), target.ElementBytes() / static_cast(KIND)) == 0; } }; struct LogicalEquivalence { RT_API_ATTRS bool operator()(const Descriptor &array, const SubscriptValue at[], const Descriptor &target) const { return IsLogicalElementTrue(array, at) == IsLogicalElementTrue(target, at /*ignored*/); } }; template struct EqualityForTargetKind { template struct Functor { RT_API_ATTRS void operator()(bool &result, const Descriptor &array, const SubscriptValue at[], const Descriptor &target) const { result = Equality{}(array, at, target); } }; }; template class NumericFindlocAccumulator { public: RT_API_ATTRS NumericFindlocAccumulator(const Descriptor &array, const Descriptor &target, bool back, TypeCategory targetCat, int targetKind, Terminator &terminator) : array_{array}, target_{target}, back_{back}, targetCat_{targetCat}, targetKind_{targetKind}, terminator_{terminator} {} RT_API_ATTRS void Reinitialize() { gotAnything_ = false; } template RT_API_ATTRS void GetResult(A *p, int zeroBasedDim = -1) { if (zeroBasedDim >= 0) { *p = gotAnything_ ? location_[zeroBasedDim] - array_.GetDimension(zeroBasedDim).LowerBound() + 1 : 0; } else if (gotAnything_) { for (int j{0}; j < rank_; ++j) { p[j] = location_[j] - array_.GetDimension(j).LowerBound() + 1; } } else { for (int j{0}; j < rank_; ++j) { p[j] = 0; } } } template RT_API_ATTRS bool AccumulateAt(const SubscriptValue at[]) { if (compareTarget(at)) { gotAnything_ = true; for (int j{0}; j < rank_; ++j) { location_[j] = at[j]; } return back_; } return true; } private: RT_API_ATTRS bool compareTarget(const SubscriptValue at[]) { bool result{false}; switch (targetCat_) { case TypeCategory::Integer: case TypeCategory::Unsigned: ApplyIntegerKind::template Functor, void>(targetKind_, terminator_, result, array_, at, target_); break; case TypeCategory::Real: ApplyFloatingPointKind::template Functor, void>(targetKind_, terminator_, result, array_, at, target_); break; case TypeCategory::Complex: ApplyFloatingPointKind::template Functor, void>(targetKind_, terminator_, result, array_, at, target_); break; default: break; } return result; } const Descriptor &array_; const Descriptor &target_; const bool back_{false}; const int rank_{array_.rank()}; bool gotAnything_{false}; SubscriptValue location_[maxRank]; const TypeCategory targetCat_; const int targetKind_; Terminator &terminator_; }; template class LocationAccumulator { public: RT_API_ATTRS LocationAccumulator( const Descriptor &array, const Descriptor &target, bool back) : array_{array}, target_{target}, back_{back} {} RT_API_ATTRS void Reinitialize() { gotAnything_ = false; } template RT_API_ATTRS void GetResult(A *p, int zeroBasedDim = -1) { if (zeroBasedDim >= 0) { *p = gotAnything_ ? location_[zeroBasedDim] - array_.GetDimension(zeroBasedDim).LowerBound() + 1 : 0; } else if (gotAnything_) { for (int j{0}; j < rank_; ++j) { p[j] = location_[j] - array_.GetDimension(j).LowerBound() + 1; } } else { // no unmasked hits? result is all zeroes for (int j{0}; j < rank_; ++j) { p[j] = 0; } } } template RT_API_ATTRS bool AccumulateAt(const SubscriptValue at[]) { if (equality_(array_, at, target_)) { gotAnything_ = true; 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()}; bool gotAnything_{false}; SubscriptValue location_[maxRank]; const EQUALITY equality_{}; }; template struct TotalNumericFindlocSource { template struct Functor { RT_API_ATTRS RT_DEVICE_NOINLINE 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 { using Accumulator = NumericFindlocAccumulator; Accumulator accumulator{ x, target, back, targetCat, targetKind, terminator}; DoTotalReduction(x, dim, mask, accumulator, "FINDLOC", terminator); ApplyIntegerKind::template Functor, void>(kind, terminator, accumulator, result); } }; }; template struct CharacterFindlocHelper { RT_API_ATTRS void operator()(Descriptor &result, const Descriptor &x, const Descriptor &target, int kind, const Descriptor *mask, bool back, Terminator &terminator) { using Accumulator = LocationAccumulator>; Accumulator accumulator{x, target, back}; DoTotalReduction(x, 0, mask, accumulator, "FINDLOC", terminator); ApplyIntegerKind::template Functor, void>( kind, terminator, accumulator, result); } }; inline RT_API_ATTRS void LogicalFindlocHelper(Descriptor &result, const Descriptor &x, const Descriptor &target, int kind, const Descriptor *mask, bool back, Terminator &terminator) { using Accumulator = LocationAccumulator; Accumulator accumulator{x, target, back}; DoTotalReduction(x, 0, mask, accumulator, "FINDLOC", terminator); ApplyIntegerKind::template Functor, void>( kind, terminator, accumulator, result); } template struct PartialNumericFindlocSource { template struct Functor { RT_API_ATTRS RT_DEVICE_NOINLINE 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 { using Accumulator = NumericFindlocAccumulator; Accumulator accumulator{ x, target, back, targetCat, targetKind, terminator}; ApplyIntegerKind::template Functor, void>(kind, terminator, result, x, dim, mask, terminator, "FINDLOC", accumulator); } }; }; template struct PartialCharacterFindlocHelper { RT_API_ATTRS void operator()(Descriptor &result, const Descriptor &x, const Descriptor &target, int kind, int dim, const Descriptor *mask, bool back, Terminator &terminator) { using Accumulator = LocationAccumulator>; Accumulator accumulator{x, target, back}; ApplyIntegerKind::template Functor, void>(kind, terminator, result, x, dim, mask, terminator, "FINDLOC", accumulator); } }; inline RT_API_ATTRS void PartialLogicalFindlocHelper(Descriptor &result, const Descriptor &x, const Descriptor &target, int kind, int dim, const Descriptor *mask, bool back, Terminator &terminator) { using Accumulator = LocationAccumulator; Accumulator accumulator{x, target, back}; ApplyIntegerKind::template Functor, void>( kind, terminator, result, x, dim, mask, terminator, "FINDLOC", accumulator); } } // namespace Fortran::runtime #endif // FLANG_RT_RUNTIME_FINDLOC_H_