diff --git a/flang/runtime/extrema.cpp b/flang/runtime/extrema.cpp --- a/flang/runtime/extrema.cpp +++ b/flang/runtime/extrema.cpp @@ -60,8 +60,10 @@ template class ExtremumLocAccumulator { public: using Type = typename COMPARE::Type; - ExtremumLocAccumulator(const Descriptor &array, std::size_t chars = 0) - : array_{array}, argRank_{array.rank()}, compare_{array.ElementBytes()} { + ExtremumLocAccumulator( + const Descriptor &array, const Descriptor *mask = nullptr) + : array_{array}, argRank_{array.rank()}, compare_{array.ElementBytes()}, + mask_(mask) { Reinitialize(); } void Reinitialize() { @@ -77,8 +79,15 @@ *p = extremumLoc_[zeroBasedDim] - array_.GetDimension(zeroBasedDim).LowerBound() + 1; } else { - for (int j{0}; j < argRank_; ++j) { - p[j] = extremumLoc_[j] - array_.GetDimension(j).LowerBound() + 1; + // Either mask is missing or it's scalar .FALSE. + if (mask_) { + // Scalar .FALSE. -- all values are zero + *p = 0; + } else { + // No mask + for (int j{0}; j < argRank_; ++j) { + p[j] = extremumLoc_[j] - array_.GetDimension(j).LowerBound() + 1; + } } } } @@ -99,6 +108,7 @@ SubscriptValue extremumLoc_[maxRank]; const Type *previous_{nullptr}; COMPARE compare_; + const Descriptor *mask_; }; template @@ -200,7 +210,7 @@ const Descriptor *mask, Terminator &terminator) { using CppType = CppTypeFor; using Accumulator = ExtremumLocAccumulator>; - Accumulator accumulator{x}; + Accumulator accumulator{x, mask}; ApplyIntegerKind::template Functor, void>( kind, terminator, result, x, dim, mask, terminator, intrinsic, accumulator); diff --git a/flang/unittests/Runtime/Reduction.cpp b/flang/unittests/Runtime/Reduction.cpp --- a/flang/unittests/Runtime/Reduction.cpp +++ b/flang/unittests/Runtime/Reduction.cpp @@ -158,12 +158,84 @@ EXPECT_EQ(scalarResult.rank(), 0); EXPECT_EQ(*scalarResult.ZeroBasedIndexedElement(0), 23); scalarResult.Destroy(); + + // Test .FALSE. scalar MASK argument + auto falseMask{MakeArray( + std::vector{}, std::vector{0})}; + RTNAME(MaxlocDim) + (loc, *array, /*KIND=*/4, /*DIM=*/2, __FILE__, __LINE__, + /*MASK=*/&*falseMask, /*BACK=*/false); + EXPECT_EQ(loc.rank(), 2); + EXPECT_EQ(loc.type().raw(), (TypeCode{TypeCategory::Integer, 4}.raw())); + EXPECT_EQ(loc.GetDimension(0).LowerBound(), 1); + EXPECT_EQ(loc.GetDimension(0).Extent(), 3); + EXPECT_EQ(loc.GetDimension(1).LowerBound(), 1); + EXPECT_EQ(loc.GetDimension(1).Extent(), 2); + for (int i{0}; i < 6; ++i) { + EXPECT_EQ(*loc.ZeroBasedIndexedElement(0), 0); + } + loc.Destroy(); + + // Test .TRUE. scalar MASK argument + auto trueMask{MakeArray( + std::vector{}, std::vector{1})}; + RTNAME(MaxlocDim) + (loc, *array, /*KIND=*/4, /*DIM=*/2, __FILE__, __LINE__, + /*MASK=*/&*trueMask, /*BACK=*/false); + EXPECT_EQ(loc.rank(), 2); + EXPECT_EQ(loc.type().raw(), (TypeCode{TypeCategory::Integer, 4}.raw())); + EXPECT_EQ(loc.GetDimension(0).LowerBound(), 1); + EXPECT_EQ(loc.GetDimension(0).Extent(), 3); + EXPECT_EQ(loc.GetDimension(1).LowerBound(), 1); + EXPECT_EQ(loc.GetDimension(1).Extent(), 2); + EXPECT_EQ(*loc.ZeroBasedIndexedElement(0), 3); + EXPECT_EQ(*loc.ZeroBasedIndexedElement(1), 4); + EXPECT_EQ(*loc.ZeroBasedIndexedElement(2), 3); + EXPECT_EQ(*loc.ZeroBasedIndexedElement(3), 3); + EXPECT_EQ(*loc.ZeroBasedIndexedElement(4), 4); + EXPECT_EQ(*loc.ZeroBasedIndexedElement(5), 4); + loc.Destroy(); + RTNAME(MinlocDim) (scalarResult, *array1, /*KIND=*/2, /*DIM=*/1, __FILE__, __LINE__, /*MASK=*/nullptr, /*BACK=*/true); EXPECT_EQ(scalarResult.rank(), 0); EXPECT_EQ(*scalarResult.ZeroBasedIndexedElement(0), 22); scalarResult.Destroy(); + + // Test .FALSE. scalar MASK argument + RTNAME(MinlocDim) + (loc, *array, /*KIND=*/4, /*DIM=*/2, __FILE__, __LINE__, + /*MASK=*/&*falseMask, /*BACK=*/false); + EXPECT_EQ(loc.rank(), 2); + EXPECT_EQ(loc.type().raw(), (TypeCode{TypeCategory::Integer, 4}.raw())); + EXPECT_EQ(loc.GetDimension(0).LowerBound(), 1); + EXPECT_EQ(loc.GetDimension(0).Extent(), 3); + EXPECT_EQ(loc.GetDimension(1).LowerBound(), 1); + EXPECT_EQ(loc.GetDimension(1).Extent(), 2); + for (int i{0}; i < 6; ++i) { + EXPECT_EQ(*loc.ZeroBasedIndexedElement(0), 0); + } + loc.Destroy(); + + // Test .TRUE. scalar MASK argument + RTNAME(MinlocDim) + (loc, *array, /*KIND=*/4, /*DIM=*/2, __FILE__, __LINE__, + /*MASK=*/&*trueMask, /*BACK=*/false); + EXPECT_EQ(loc.rank(), 2); + EXPECT_EQ(loc.type().raw(), (TypeCode{TypeCategory::Integer, 4}.raw())); + EXPECT_EQ(loc.GetDimension(0).LowerBound(), 1); + EXPECT_EQ(loc.GetDimension(0).Extent(), 3); + EXPECT_EQ(loc.GetDimension(1).LowerBound(), 1); + EXPECT_EQ(loc.GetDimension(1).Extent(), 2); + EXPECT_EQ(*loc.ZeroBasedIndexedElement(0), 4); + EXPECT_EQ(*loc.ZeroBasedIndexedElement(1), 3); + EXPECT_EQ(*loc.ZeroBasedIndexedElement(2), 4); + EXPECT_EQ(*loc.ZeroBasedIndexedElement(3), 4); + EXPECT_EQ(*loc.ZeroBasedIndexedElement(4), 3); + EXPECT_EQ(*loc.ZeroBasedIndexedElement(5), 2); + loc.Destroy(); + RTNAME(MaxvalDim) (scalarResult, *array1, /*DIM=*/1, __FILE__, __LINE__, /*MASK=*/nullptr); EXPECT_EQ(scalarResult.rank(), 0);