diff --git a/flang/runtime/transformational.cpp b/flang/runtime/transformational.cpp --- a/flang/runtime/transformational.cpp +++ b/flang/runtime/transformational.cpp @@ -130,7 +130,7 @@ extern "C" { -// CSHIFT of rank > 1 +// CSHIFT where rank of ARRAY argument > 1 void RTNAME(Cshift)(Descriptor &result, const Descriptor &source, const Descriptor &shift, int dim, const char *sourceFile, int line) { Terminator terminator{sourceFile, line}; @@ -172,7 +172,7 @@ } } -// CSHIFT of vector +// CSHIFT where rank of ARRAY argument == 1 void RTNAME(CshiftVector)(Descriptor &result, const Descriptor &source, std::int64_t shift, const char *sourceFile, int line) { Terminator terminator{sourceFile, line}; @@ -184,6 +184,9 @@ for (SubscriptValue j{0}; j < extent; ++j) { SubscriptValue resultAt{1 + j}; SubscriptValue sourceAt{lb + (j + shift) % extent}; + if (sourceAt < 0) { + sourceAt += extent; + } CopyElement(result, &resultAt, source, &sourceAt, terminator); } } diff --git a/flang/unittests/RuntimeGTest/Transformational.cpp b/flang/unittests/RuntimeGTest/Transformational.cpp --- a/flang/unittests/RuntimeGTest/Transformational.cpp +++ b/flang/unittests/RuntimeGTest/Transformational.cpp @@ -60,6 +60,39 @@ } result.Destroy(); + // VECTOR 1 3 5 2 4 6 + auto vector{MakeArray( + std::vector{6}, std::vector{1, 2, 3, 4, 5, 6})}; + vector->GetDimension(0).SetLowerBound(0); + StaticDescriptor<1, true> vectorDesc; + Descriptor &vectorResult{vectorDesc.descriptor()}; + + RTNAME(CshiftVector)(vectorResult, *vector, 2, __FILE__, __LINE__); + EXPECT_EQ(vectorResult.type(), array->type()); + EXPECT_EQ(vectorResult.rank(), 1); + EXPECT_EQ(vectorResult.GetDimension(0).LowerBound(), 1); + EXPECT_EQ(vectorResult.GetDimension(0).Extent(), 6); + EXPECT_EQ(vectorResult.type(), (TypeCode{TypeCategory::Integer, 4})); + static std::int32_t cshiftExpect3[6]{3, 4, 5, 6, 1, 2}; + for (int j{0}; j < 6; ++j) { + EXPECT_EQ(*vectorResult.ZeroBasedIndexedElement(j), + cshiftExpect3[j]); + } + vectorResult.Destroy(); + + RTNAME(CshiftVector)(vectorResult, *vector, -2, __FILE__, __LINE__); + EXPECT_EQ(vectorResult.type(), array->type()); + EXPECT_EQ(vectorResult.rank(), 1); + EXPECT_EQ(vectorResult.GetDimension(0).LowerBound(), 1); + EXPECT_EQ(vectorResult.GetDimension(0).Extent(), 6); + EXPECT_EQ(vectorResult.type(), (TypeCode{TypeCategory::Integer, 4})); + static std::int32_t cshiftExpect4[6]{5, 6, 1, 2, 3, 4}; + for (int j{0}; j < 6; ++j) { + EXPECT_EQ(*vectorResult.ZeroBasedIndexedElement(j), + cshiftExpect4[j]); + } + vectorResult.Destroy(); + auto boundary{MakeArray( std::vector{3}, std::vector{-1, -2, -3})}; boundary->GetDimension(0).SetLowerBound(9); // shouldn't matter