diff --git a/flang/include/flang/Runtime/ragged.h b/flang/include/flang/Runtime/ragged.h new file mode 100644 --- /dev/null +++ b/flang/include/flang/Runtime/ragged.h @@ -0,0 +1,33 @@ +//===-- Runtime/ragged.h ----------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef FORTRAN_RUNTIME_RAGGED_H_ +#define FORTRAN_RUNTIME_RAGGED_H_ + +#include "flang/Runtime/entry-names.h" +#include + +namespace Fortran::runtime { +struct RaggedArrayHeader { + std::uint64_t flags{0u}; + void *bufferPointer{nullptr}; + std::int64_t *extentPointer{nullptr}; + + bool isIndirection() const { return flags & 1; } + std::size_t rank() const { return flags >> 1; } +}; + +extern "C" { +// Helper for allocation of ragged array buffer blocks. +void *RTNAME(RaggedArrayAllocate)( + void *, bool, std::int64_t, std::int64_t, std::int64_t *); +// Helper for deallocation of ragged array buffers. +void RTNAME(RaggedArrayDeallocate)(void *); +} // extern "C" +} // namespace Fortran::runtime +#endif // FORTRAN_RUNTIME_RAGGED_H_ diff --git a/flang/runtime/CMakeLists.txt b/flang/runtime/CMakeLists.txt --- a/flang/runtime/CMakeLists.txt +++ b/flang/runtime/CMakeLists.txt @@ -63,6 +63,7 @@ misc-intrinsic.cpp namelist.cpp numeric.cpp + ragged.cpp random.cpp reduction.cpp pointer.cpp diff --git a/flang/runtime/ragged.cpp b/flang/runtime/ragged.cpp new file mode 100644 --- /dev/null +++ b/flang/runtime/ragged.cpp @@ -0,0 +1,73 @@ +//===-- runtime/ragged.cpp ------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "flang/Runtime/ragged.h" +#include + +namespace Fortran::runtime { + +static RaggedArrayHeader *RaggedArrayAllocate(RaggedArrayHeader *header, + bool isHeader, std::int64_t rank, std::int64_t elementSize, + std::int64_t *extentVector) { + if (header && rank) { + std::int64_t size = 1; + for (std::int64_t counter{0}; counter < rank; ++counter) { + size *= extentVector[counter]; + if (size <= 0) { + return nullptr; + } + } + header->flags = (rank << 1) | isHeader; + header->extentPointer = extentVector; + if (isHeader) { + header->bufferPointer = new RaggedArrayHeader[size]; + } else { + header->bufferPointer = + static_cast(std::calloc(elementSize, size)); + } + return header; + } else { + return nullptr; + } +} + +// Deallocate a ragged array from the heap. +static void RaggedArrayDeallocate(RaggedArrayHeader *raggedArrayHeader) { + if (raggedArrayHeader) { + if (std::size_t end{raggedArrayHeader->rank()}) { + if (raggedArrayHeader->isIndirection()) { + std::size_t linearExtent{1u}; + for (std::size_t counter{0u}; counter < end && linearExtent > 0; + ++counter) { + linearExtent *= raggedArrayHeader->extentPointer[counter]; + } + for (std::size_t counter{0u}; counter < linearExtent; ++counter) { + RaggedArrayDeallocate(&static_cast( + raggedArrayHeader->bufferPointer)[counter]); + } + } + std::free(raggedArrayHeader->bufferPointer); + std::free(raggedArrayHeader->extentPointer); + raggedArrayHeader->flags = 0u; + } + } +} + +extern "C" { +void *RTNAME(RaggedArrayAllocate)(void *header, bool isHeader, + std::int64_t rank, std::int64_t elementSize, std::int64_t *extentVector) { + auto *result = RaggedArrayAllocate(static_cast(header), + isHeader, rank, elementSize, extentVector); + return static_cast(result); +} + +void RTNAME(RaggedArrayDeallocate)(void *raggedArrayHeader) { + RaggedArrayDeallocate(static_cast(raggedArrayHeader)); +} +} // extern "C" +} // namespace Fortran::runtime diff --git a/flang/unittests/Runtime/CMakeLists.txt b/flang/unittests/Runtime/CMakeLists.txt --- a/flang/unittests/Runtime/CMakeLists.txt +++ b/flang/unittests/Runtime/CMakeLists.txt @@ -11,6 +11,7 @@ Namelist.cpp Numeric.cpp NumericalFormatTest.cpp + Ragged.cpp Random.cpp Reduction.cpp RuntimeCrashTest.cpp diff --git a/flang/unittests/Runtime/Ragged.cpp b/flang/unittests/Runtime/Ragged.cpp new file mode 100644 --- /dev/null +++ b/flang/unittests/Runtime/Ragged.cpp @@ -0,0 +1,33 @@ +//===-- flang/unittests/Runtime/Ragged.cpp ----------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "flang/Runtime/ragged.h" +#include "gtest/gtest.h" + +using namespace Fortran::runtime; + +TEST(Ragged, RaggedArrayAllocateDeallocateTest) { + struct RaggedArrayHeader header; + unsigned rank = 2; + int64_t *extents = new int64_t[2]; + extents[0] = 10; + extents[1] = 100; + RaggedArrayHeader *ret = (RaggedArrayHeader *)_FortranARaggedArrayAllocate( + &header, false, rank, 32, extents); + EXPECT_TRUE(ret != nullptr); + EXPECT_EQ(4u, ret->flags); + EXPECT_TRUE(ret->bufferPointer != nullptr); + EXPECT_EQ(extents, ret->extentPointer); + EXPECT_EQ(10, ret->extentPointer[0]); + EXPECT_EQ(100, ret->extentPointer[1]); + EXPECT_EQ(rank, ret->rank()); + EXPECT_FALSE(ret->isIndirection()); + + _FortranARaggedArrayDeallocate(ret); + EXPECT_EQ(0u, ret->flags); +}