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(); } @@ -72,13 +72,21 @@ previous_ = nullptr; } int argRank() const { return argRank_; } - template void GetResult(A *p, int zeroBasedDim = -1) { + template + void GetResult(A *p, int zeroBasedDim = -1, bool scalarFalseMask = false) { if (zeroBasedDim >= 0) { *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 (scalarFalseMask) { + // 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; + } } } } @@ -307,7 +315,9 @@ void Reinitialize() { extremum_ = MaxOrMinIdentity::Value(); } - template void GetResult(A *p, int /*zeroBasedDim*/ = -1) const { + template + void GetResult( + A *p, int /*zeroBasedDim*/ = -1, bool /*scalarFalseMask*/ = false) const { *p = extremum_; } bool Accumulate(Type x) { @@ -401,7 +411,9 @@ explicit CharacterExtremumAccumulator(const Descriptor &array) : array_{array}, charLen_{array_.ElementBytes() / KIND} {} void Reinitialize() { extremum_ = nullptr; } - template void GetResult(A *p, int /*zeroBasedDim*/ = -1) const { + template + void GetResult( + A *p, int /*zeroBasedDim*/ = -1, bool /*scalarFalseMask*/ = false) const { static_assert(std::is_same_v); if (extremum_) { std::memcpy(p, extremum_, charLen_); @@ -601,7 +613,9 @@ using AccumType = CppTypeFor; explicit Norm2Accumulator(const Descriptor &array) : array_{array} {} void Reinitialize() { max_ = sum_ = 0; } - template void GetResult(A *p, int /*zeroBasedDim*/ = -1) const { + template + void GetResult( + A *p, int /*zeroBasedDim*/ = -1, bool /*scalarFalseMask*/ = false) const { // m * sqrt(1 + sum((others(:)/m)**2)) *p = static_cast(max_ * std::sqrt(1 + sum_)); } diff --git a/flang/runtime/findloc.cpp b/flang/runtime/findloc.cpp --- a/flang/runtime/findloc.cpp +++ b/flang/runtime/findloc.cpp @@ -94,7 +94,9 @@ location_[j] = 0; } } - template void GetResult(A *p, int zeroBasedDim = -1) { + template + void GetResult( + A *p, int zeroBasedDim = -1, bool /*scalarFalseMask*/ = false) { if (zeroBasedDim >= 0) { *p = location_[zeroBasedDim] - array_.GetDimension(zeroBasedDim).LowerBound() + 1; diff --git a/flang/runtime/product.cpp b/flang/runtime/product.cpp --- a/flang/runtime/product.cpp +++ b/flang/runtime/product.cpp @@ -20,7 +20,9 @@ explicit NonComplexProductAccumulator(const Descriptor &array) : array_{array} {} void Reinitialize() { product_ = 1; } - template void GetResult(A *p, int /*zeroBasedDim*/ = -1) const { + template + void GetResult( + A *p, int /*zeroBasedDim*/ = -1, bool /*scalarFalseMask*/ = false) const { *p = static_cast(product_); } template bool AccumulateAt(const SubscriptValue at[]) { @@ -37,7 +39,9 @@ public: explicit ComplexProductAccumulator(const Descriptor &array) : array_{array} {} void Reinitialize() { product_ = std::complex{1, 0}; } - template void GetResult(A *p, int /*zeroBasedDim*/ = -1) const { + template + void GetResult( + A *p, int /*zeroBasedDim*/ = -1, bool /*scalarFalseMask*/ = false) const { using ResultPart = typename A::value_type; *p = {static_cast(product_.real()), static_cast(product_.imag())}; diff --git a/flang/runtime/reduction-templates.h b/flang/runtime/reduction-templates.h --- a/flang/runtime/reduction-templates.h +++ b/flang/runtime/reduction-templates.h @@ -214,7 +214,8 @@ // scalar MASK=.FALSE. accumulator.Reinitialize(); for (auto n{result.Elements()}; n-- > 0; result.IncrementSubscripts(at)) { - accumulator.GetResult(result.Element(at)); + accumulator.GetResult(result.Element(at), /*zeroBasedDim=*/-1, + /*scalarFalseMask=*/true); } return; } diff --git a/flang/runtime/reduction.cpp b/flang/runtime/reduction.cpp --- a/flang/runtime/reduction.cpp +++ b/flang/runtime/reduction.cpp @@ -26,7 +26,9 @@ public: explicit IntegerAndAccumulator(const Descriptor &array) : array_{array} {} void Reinitialize() { and_ = ~INTERMEDIATE{0}; } - template void GetResult(A *p, int /*zeroBasedDim*/ = -1) const { + template + void GetResult( + A *p, int /*zeroBasedDim*/ = -1, bool /*scalarFalseMask*/ = false) const { *p = static_cast(and_); } template bool AccumulateAt(const SubscriptValue at[]) { @@ -43,7 +45,9 @@ public: explicit IntegerOrAccumulator(const Descriptor &array) : array_{array} {} void Reinitialize() { or_ = 0; } - template void GetResult(A *p, int /*zeroBasedDim*/ = -1) const { + template + void GetResult( + A *p, int /*zeroBasedDim*/ = -1, bool /*scalarFalseMask*/ = false) const { *p = static_cast(or_); } template bool AccumulateAt(const SubscriptValue at[]) { @@ -60,7 +64,9 @@ public: explicit IntegerXorAccumulator(const Descriptor &array) : array_{array} {} void Reinitialize() { xor_ = 0; } - template void GetResult(A *p, int /*zeroBasedDim*/ = -1) const { + template + void GetResult( + A *p, int /*zeroBasedDim*/ = -1, bool /*scalarFalseMask*/ = false) const { *p = static_cast(xor_); } template bool AccumulateAt(const SubscriptValue at[]) { diff --git a/flang/runtime/sum.cpp b/flang/runtime/sum.cpp --- a/flang/runtime/sum.cpp +++ b/flang/runtime/sum.cpp @@ -24,7 +24,9 @@ public: explicit IntegerSumAccumulator(const Descriptor &array) : array_{array} {} void Reinitialize() { sum_ = 0; } - template void GetResult(A *p, int /*zeroBasedDim*/ = -1) const { + template + void GetResult( + A *p, int /*zeroBasedDim*/ = -1, bool /*scalarFalseMask*/ = false) const { *p = static_cast(sum_); } template bool AccumulateAt(const SubscriptValue at[]) { @@ -42,7 +44,9 @@ explicit RealSumAccumulator(const Descriptor &array) : array_{array} {} void Reinitialize() { sum_ = correction_ = 0; } template A Result() const { return sum_; } - template void GetResult(A *p, int /*zeroBasedDim*/ = -1) const { + template + void GetResult( + A *p, int /*zeroBasedDim*/ = -1, bool /*scalarFalseMask*/ = false) const { *p = Result(); } template bool Accumulate(A x) { @@ -69,7 +73,9 @@ reals_.Reinitialize(); imaginaries_.Reinitialize(); } - template void GetResult(A *p, int /*zeroBasedDim*/ = -1) const { + template + void GetResult( + A *p, int /*zeroBasedDim*/ = -1, bool /*scalarFalseMask*/ = false) const { using ResultPart = typename A::value_type; *p = {reals_.template Result(), imaginaries_.template Result()}; 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);