//===-- 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 #include namespace Fortran::runtime { template struct Equality { using Type1 = CppTypeFor; using Type2 = CppTypeFor; bool operator()(const Descriptor &array, const SubscriptValue at[], const Descriptor &target) const { return *array.Element(at) == *target.OffsetElement(); } }; template struct Equality { using Type1 = CppTypeFor; using Type2 = CppTypeFor; 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; 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; 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; 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 { bool operator()(const Descriptor &array, const SubscriptValue at[], const Descriptor &target) const { return IsLogicalElementTrue(array, at) == IsLogicalElementTrue(target, at /*ignored*/); } }; template 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 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 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 struct TotalNumericFindlocHelper { template 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; using Accumulator = LocationAccumulator; Accumulator accumulator{x, target, back}; DoTotalReduction(x, dim, mask, accumulator, "FINDLOC", terminator); ApplyIntegerKind::template Functor, void>(kind, terminator, accumulator, result); } }; }; template class HELPER> struct NumericFindlocHelper { template 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::template Functor, void>( targetKind, terminator, result, x, target, kind, dim, mask, back, terminator); break; case TypeCategory::Real: ApplyFloatingPointKind< HELPER::template Functor, void>( targetKind, terminator, result, x, target, kind, dim, mask, back, terminator); break; case TypeCategory::Complex: ApplyFloatingPointKind< HELPER::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(targetCat), static_cast(CAT)); } } }; }; template struct CharacterFindlocHelper { 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); } }; static 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); } 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::template Functor, void>(xType->second, terminator, targetType->first, targetType->second, result, x, target, kind, 0, mask, back, terminator); break; case TypeCategory::Real: ApplyFloatingPointKind::template Functor, void>(xType->second, terminator, targetType->first, targetType->second, result, x, target, kind, 0, mask, back, terminator); break; case TypeCategory::Complex: ApplyFloatingPointKind::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(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 struct PartialNumericFindlocHelper { template 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; using Accumulator = LocationAccumulator; Accumulator accumulator{x, target, back}; ApplyIntegerKind::template Functor, void>(kind, terminator, result, x, dim, mask, terminator, "FINDLOC", accumulator); } }; }; template 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>; Accumulator accumulator{x, target, back}; ApplyIntegerKind::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; Accumulator accumulator{x, target, back}; ApplyIntegerKind::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::template Functor, void>(xType->second, terminator, targetType->first, targetType->second, result, x, target, kind, dim, mask, back, terminator); break; case TypeCategory::Real: ApplyFloatingPointKind::template Functor, void>(xType->second, terminator, targetType->first, targetType->second, result, x, target, kind, dim, mask, back, terminator); break; case TypeCategory::Complex: ApplyFloatingPointKind::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(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