diff --git a/flang/runtime/extrema.cpp b/flang/runtime/extrema.cpp --- a/flang/runtime/extrema.cpp +++ b/flang/runtime/extrema.cpp @@ -60,7 +60,7 @@ template class ExtremumLocAccumulator { public: using Type = typename COMPARE::Type; - ExtremumLocAccumulator(const Descriptor &array, std::size_t chars = 0) + ExtremumLocAccumulator(const Descriptor &array) : array_{array}, argRank_{array.rank()}, compare_{array.ElementBytes()} { Reinitialize(); } @@ -241,24 +241,39 @@ CheckIntegerKind(terminator, kind, intrinsic); auto catKind{x.type().GetCategoryAndKind()}; RUNTIME_CHECK(terminator, catKind.has_value()); + const Descriptor *maskToUse{mask}; + SubscriptValue maskAt[maxRank]; // contents unused + if (mask && mask->rank() == 0) { + if (IsLogicalElementTrue(*mask, maskAt)) { + // A scalar MASK that's .TRUE. In this case, just get rid of the MASK. + maskToUse = nullptr; + } else { + // For scalar MASK arguments that are .FALSE., return all zeroes + CreatePartialReductionResult(result, x, dim, terminator, intrinsic, + TypeCode{TypeCategory::Integer, kind}); + std::memset( + result.OffsetElement(), 0, result.Elements() * result.ElementBytes()); + return; + } + } switch (catKind->first) { case TypeCategory::Integer: ApplyIntegerKind::template Functor, void>(catKind->second, terminator, intrinsic, result, x, kind, dim, - mask, back, terminator); + maskToUse, back, terminator); break; case TypeCategory::Real: ApplyFloatingPointKind::template Functor, void>(catKind->second, terminator, intrinsic, result, x, kind, dim, - mask, back, terminator); + maskToUse, back, terminator); break; case TypeCategory::Character: ApplyCharacterKind::template Functor, void>(catKind->second, terminator, intrinsic, result, x, kind, dim, - mask, back, terminator); + maskToUse, back, terminator); break; default: terminator.Crash( 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);