Index: flang/runtime/reduction-templates.h =================================================================== --- flang/runtime/reduction-templates.h +++ flang/runtime/reduction-templates.h @@ -196,7 +196,16 @@ CreatePartialReductionResult( result, x, dim, terminator, intrinsic, TypeCode{CAT, KIND}); SubscriptValue at[maxRank]; - result.GetLowerBounds(at); + /* F18 16.9.78 "Findloc", F18 16.9.127 "Maxloc", F18 16.9.128 "Maxval", + * F18 16.9.133 "Minloc", and F18 16.9.134 "Minval" + * Result can be a scalar, which means the result rank is 0 and number + * of elements is 1. So, directly set at[0] = 1 in that case since + * GetLowerBounds() does not do anything when rank == 0. + */ + if (result.rank() == 0 && result.Elements() == 1) + at[0] = 1; // needed for handling scalar result below. + else + result.GetLowerBounds(at); INTERNAL_CHECK(at[0] == 1); using CppType = CppTypeFor; if (mask) { Index: flang/runtime/reduction.cpp =================================================================== --- flang/runtime/reduction.cpp +++ flang/runtime/reduction.cpp @@ -266,7 +266,13 @@ CreatePartialReductionResult( result, x, dim, terminator, intrinsic, x.type()); SubscriptValue at[maxRank]; - result.GetLowerBounds(at); + /* F18 16.9.10 "All" and F18 16.9.13 "Any" result can be scalar if + * rank of MASK is 1 or DIM is not present. + */ + if (result.rank() == 0 && result.Elements() == 1) + at[0] = 1; // needed for handling scalar result below. + else + result.GetLowerBounds(at); INTERNAL_CHECK(at[0] == 1); using CppType = CppTypeFor; for (auto n{result.Elements()}; n-- > 0; result.IncrementSubscripts(at)) { @@ -314,7 +320,13 @@ CreatePartialReductionResult(result, x, dim, terminator, "COUNT", TypeCode{TypeCategory::Integer, KIND}); SubscriptValue at[maxRank]; - result.GetLowerBounds(at); + /* F18 16.9.56 "Count" result can be scalar if rank of MASK is 1 or DIM is + * not present. + */ + if (result.rank() == 0 && result.Elements() == 1) + at[0] = 1; // needed for handling scalar result below. + else + result.GetLowerBounds(at); INTERNAL_CHECK(at[0] == 1); using CppType = CppTypeFor; for (auto n{result.Elements()}; n-- > 0; result.IncrementSubscripts(at)) { Index: flang/unittests/RuntimeGTest/Reduction.cpp =================================================================== --- flang/unittests/RuntimeGTest/Reduction.cpp +++ flang/unittests/RuntimeGTest/Reduction.cpp @@ -146,6 +146,34 @@ EXPECT_EQ(*loc.ZeroBasedIndexedElement(10), 2); // 22 EXPECT_EQ(*loc.ZeroBasedIndexedElement(11), 2); // 22 loc.Destroy(); + // Test scalar result for MaxlocDim, MinlocDim, MaxvalDim, MinvalDim. + // A scalar result occurs when you have a rank 1 array and dim == 1. + std::vector shape1{24}; + auto array1{MakeArray(shape1, rawData)}; + StaticDescriptor<0, true> statDesc0; + Descriptor &scalarResult{statDesc0.descriptor()}; + RTNAME(MaxlocDim) + (scalarResult, *array1, /*KIND=*/2, /*DIM=*/1, __FILE__, __LINE__, + /*MASK=*/nullptr, /*BACK=*/false); + EXPECT_EQ(scalarResult.rank(), 0); + EXPECT_EQ(*scalarResult.ZeroBasedIndexedElement(0), 23); + scalarResult.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(); + RTNAME(MaxvalDim) + (scalarResult, *array1, /*DIM=*/1, __FILE__, __LINE__, /*MASK=*/nullptr); + EXPECT_EQ(scalarResult.rank(), 0); + EXPECT_EQ(*scalarResult.ZeroBasedIndexedElement(0), 22.0); + scalarResult.Destroy(); + RTNAME(MinvalDim) + (scalarResult, *array1, /*DIM=*/1, __FILE__, __LINE__, /*MASK=*/nullptr); + EXPECT_EQ(scalarResult.rank(), 0); + EXPECT_EQ(*scalarResult.ZeroBasedIndexedElement(0), -21.0); + scalarResult.Destroy(); } TEST(Reductions, Character) { @@ -269,6 +297,17 @@ EXPECT_EQ(*res.ZeroBasedIndexedElement(0), 0); EXPECT_EQ(*res.ZeroBasedIndexedElement(1), 0); res.Destroy(); + // Test scalar result for AllDim. + // A scalar result occurs when you have a rank 1 array. + std::vector shape1{4}; + auto array1{MakeArray( + shape1, std::vector{false, false, true, true})}; + StaticDescriptor<0, true> statDesc0; + Descriptor &scalarResult{statDesc0.descriptor()}; + RTNAME(AllDim)(scalarResult, *array1, /*DIM=*/1, __FILE__, __LINE__); + EXPECT_EQ(scalarResult.rank(), 0); + EXPECT_EQ(*scalarResult.ZeroBasedIndexedElement(0), 0); + scalarResult.Destroy(); RTNAME(AnyDim)(res, *array, /*DIM=*/1, __FILE__, __LINE__); EXPECT_EQ(res.rank(), 1); EXPECT_EQ(res.type().raw(), (TypeCode{TypeCategory::Logical, 4}.raw())); @@ -285,6 +324,12 @@ EXPECT_EQ(*res.ZeroBasedIndexedElement(0), 1); EXPECT_EQ(*res.ZeroBasedIndexedElement(1), 1); res.Destroy(); + // Test scalar result for AnyDim. + // A scalar result occurs when you have a rank 1 array. + RTNAME(AnyDim)(scalarResult, *array1, /*DIM=*/1, __FILE__, __LINE__); + EXPECT_EQ(scalarResult.rank(), 0); + EXPECT_EQ(*scalarResult.ZeroBasedIndexedElement(0), 1); + scalarResult.Destroy(); RTNAME(ParityDim)(res, *array, /*DIM=*/1, __FILE__, __LINE__); EXPECT_EQ(res.rank(), 1); EXPECT_EQ(res.type().raw(), (TypeCode{TypeCategory::Logical, 4}.raw())); @@ -301,6 +346,12 @@ EXPECT_EQ(*res.ZeroBasedIndexedElement(0), 1); EXPECT_EQ(*res.ZeroBasedIndexedElement(1), 1); res.Destroy(); + // Test scalar result for ParityDim. + // A scalar result occurs when you have a rank 1 array. + RTNAME(ParityDim)(scalarResult, *array1, /*DIM=*/1, __FILE__, __LINE__); + EXPECT_EQ(scalarResult.rank(), 0); + EXPECT_EQ(*scalarResult.ZeroBasedIndexedElement(0), 0); + scalarResult.Destroy(); RTNAME(CountDim)(res, *array, /*DIM=*/1, /*KIND=*/4, __FILE__, __LINE__); EXPECT_EQ(res.rank(), 1); EXPECT_EQ(res.type().raw(), (TypeCode{TypeCategory::Integer, 4}.raw())); @@ -317,6 +368,13 @@ EXPECT_EQ(*res.ZeroBasedIndexedElement(0), 1); EXPECT_EQ(*res.ZeroBasedIndexedElement(1), 1); res.Destroy(); + // Test scalar result for CountDim. + // A scalar result occurs when you have a rank 1 array and dim == 1. + RTNAME(CountDim) + (scalarResult, *array1, /*DIM=*/1, /*KIND=*/8, __FILE__, __LINE__); + EXPECT_EQ(scalarResult.rank(), 0); + EXPECT_EQ(*scalarResult.ZeroBasedIndexedElement(0), 2); + scalarResult.Destroy(); bool boolValue{false}; Descriptor &target{statDesc[1].descriptor()}; target.Establish(TypeCategory::Logical, 1, static_cast(&boolValue), 0, @@ -436,6 +494,21 @@ EXPECT_EQ(*res.ZeroBasedIndexedElement(0), 2); EXPECT_EQ(*res.ZeroBasedIndexedElement(1), 0); res.Destroy(); + // Test scalar result for FindlocDim. + // A scalar result occurs when you have a rank 1 array, value, and dim == 1. + std::vector shape1{6}; + auto realArray1{MakeArray(shape1, + std::vector{0.0, -0.0, 1.0, 3.14, + std::numeric_limits::quiet_NaN(), + std::numeric_limits::infinity()})}; + StaticDescriptor<0, true> statDesc0; + Descriptor &scalarResult{statDesc0.descriptor()}; + RTNAME(FindlocDim) + (scalarResult, *realArray1, target, 8, /*DIM=*/1, __FILE__, __LINE__, nullptr, + /*BACK=*/false); + EXPECT_EQ(scalarResult.rank(), 0); + EXPECT_EQ(*scalarResult.ZeroBasedIndexedElement(0), 3); + scalarResult.Destroy(); } TEST(Reductions, DotProduct) {