Skip to content

Commit 6116ff2

Browse files
[flang][runtime] Add ragged array runtime functions
This patch adds the runtime function to allocate and deallocate ragged arrays. This patch is part of the upstreaming effort from fir-dev branch. Reviewed By: klausler Differential Revision: https://reviews.llvm.org/D114534 Co-authored-by: Eric Schweitz <[email protected]>
1 parent 220854a commit 6116ff2

File tree

5 files changed

+178
-0
lines changed

5 files changed

+178
-0
lines changed
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
//===-- Runtime/ragged.h ----------------------------------------*- C++ -*-===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#ifndef FORTRAN_RUNTIME_RAGGED_H_
10+
#define FORTRAN_RUNTIME_RAGGED_H_
11+
12+
#include "flang/Runtime/entry-names.h"
13+
#include <cstdint>
14+
15+
namespace Fortran::runtime {
16+
17+
// A ragged array header block.
18+
// The header block is used to create the "array of arrays" ragged data
19+
// structure. It contains a pair in `flags` to indicate if the header points to
20+
// an array of headers (isIndirection) or data elements and the rank of the
21+
// pointed-to array. The rank is the length of the extents vector accessed
22+
// through `extentPointer`. The `bufferPointer` is overloaded and is null,
23+
// points to an array of headers (isIndirection), or data.
24+
// By default, a header is set to zero, which is its unused state.
25+
// The layout of a ragged buffer header is mirrored in the compiler.
26+
struct RaggedArrayHeader {
27+
bool indirection{false};
28+
std::uint8_t rank;
29+
void *bufferPointer{nullptr};
30+
std::int64_t *extentPointer{nullptr};
31+
32+
bool isIndirection() { return indirection; }
33+
std::uint8_t getRank() { return rank; }
34+
};
35+
36+
RaggedArrayHeader *RaggedArrayAllocate(
37+
RaggedArrayHeader *, bool, std::int64_t, std::int64_t, std::int64_t *);
38+
39+
void RaggedArrayDeallocate(RaggedArrayHeader *);
40+
41+
extern "C" {
42+
43+
// For more on ragged arrays see https://en.wikipedia.org/wiki/Jagged_array. The
44+
// Flang compiler allocates ragged arrays as a generalization for
45+
// non-rectangular array temporaries. Ragged arrays can be allocated recursively
46+
// and on demand. Structurally, each leaf is an optional rectangular array of
47+
// elements. The shape of each leaf is independent and may be computed on
48+
// demand. Each branch node is an optional, possibly sparse rectangular array of
49+
// headers. The shape of each branch is independent and may be computed on
50+
// demand. Ragged arrays preserve a correspondence between a multidimensional
51+
// iteration space and array access vectors, which is helpful for dependence
52+
// analysis.
53+
54+
// Runtime helper for allocation of ragged array buffers.
55+
// A pointer to the header block to be allocated is given as header. The flag
56+
// isHeader indicates if a block of headers or data is to be allocated. A
57+
// non-negative rank indicates the length of the extentVector, which is a list
58+
// of non-negative extents. elementSize is the size of a data element in the
59+
// rectangular space defined by the extentVector.
60+
void *RTNAME(RaggedArrayAllocate)(void *header, bool isHeader,
61+
std::int64_t rank, std::int64_t elementSize, std::int64_t *extentVector);
62+
63+
// Runtime helper for deallocation of ragged array buffers. The root header of
64+
// the ragged array structure is passed to deallocate the entire ragged array.
65+
void RTNAME(RaggedArrayDeallocate)(void *raggedArrayHeader);
66+
67+
} // extern "C"
68+
} // namespace Fortran::runtime
69+
#endif // FORTRAN_RUNTIME_RAGGED_H_

flang/runtime/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ add_flang_library(FortranRuntime
6363
misc-intrinsic.cpp
6464
namelist.cpp
6565
numeric.cpp
66+
ragged.cpp
6667
random.cpp
6768
reduction.cpp
6869
pointer.cpp

flang/runtime/ragged.cpp

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
//===-- runtime/ragged.cpp ------------------------------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#include "flang/Runtime/ragged.h"
10+
#include <cstdlib>
11+
12+
namespace Fortran::runtime {
13+
14+
RaggedArrayHeader *RaggedArrayAllocate(RaggedArrayHeader *header, bool isHeader,
15+
std::int64_t rank, std::int64_t elementSize, std::int64_t *extentVector) {
16+
if (header && rank) {
17+
std::int64_t size{1};
18+
for (std::int64_t counter{0}; counter < rank; ++counter) {
19+
size *= extentVector[counter];
20+
if (size <= 0) {
21+
return nullptr;
22+
}
23+
}
24+
header->indirection = isHeader;
25+
header->rank = rank;
26+
header->extentPointer = extentVector;
27+
if (isHeader) {
28+
header->bufferPointer = std::malloc(sizeof(RaggedArrayHeader) * size);
29+
} else {
30+
header->bufferPointer =
31+
static_cast<void *>(std::calloc(elementSize, size));
32+
}
33+
return header;
34+
} else {
35+
return nullptr;
36+
}
37+
}
38+
39+
// Deallocate a ragged array from the heap.
40+
void RaggedArrayDeallocate(RaggedArrayHeader *raggedArrayHeader) {
41+
if (raggedArrayHeader) {
42+
if (std::size_t end{raggedArrayHeader->getRank()}) {
43+
if (raggedArrayHeader->isIndirection()) {
44+
std::size_t linearExtent{1u};
45+
for (std::size_t counter{0u}; counter < end && linearExtent > 0;
46+
++counter) {
47+
linearExtent *= raggedArrayHeader->extentPointer[counter];
48+
}
49+
for (std::size_t counter{0u}; counter < linearExtent; ++counter) {
50+
RaggedArrayDeallocate(&static_cast<RaggedArrayHeader *>(
51+
raggedArrayHeader->bufferPointer)[counter]);
52+
}
53+
}
54+
std::free(raggedArrayHeader->bufferPointer);
55+
std::free(raggedArrayHeader->extentPointer);
56+
raggedArrayHeader->indirection = false;
57+
raggedArrayHeader->rank = 0u;
58+
}
59+
}
60+
}
61+
62+
extern "C" {
63+
void *RTNAME(RaggedArrayAllocate)(void *header, bool isHeader,
64+
std::int64_t rank, std::int64_t elementSize, std::int64_t *extentVector) {
65+
auto *result = RaggedArrayAllocate(static_cast<RaggedArrayHeader *>(header),
66+
isHeader, rank, elementSize, extentVector);
67+
return static_cast<void *>(result);
68+
}
69+
70+
void RTNAME(RaggedArrayDeallocate)(void *raggedArrayHeader) {
71+
RaggedArrayDeallocate(static_cast<RaggedArrayHeader *>(raggedArrayHeader));
72+
}
73+
} // extern "C"
74+
} // namespace Fortran::runtime

flang/unittests/Runtime/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ add_flang_unittest(FlangRuntimeTests
1111
Namelist.cpp
1212
Numeric.cpp
1313
NumericalFormatTest.cpp
14+
Ragged.cpp
1415
Random.cpp
1516
Reduction.cpp
1617
RuntimeCrashTest.cpp

flang/unittests/Runtime/Ragged.cpp

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
//===-- flang/unittests/Runtime/Ragged.cpp ----------------------*- C++ -*-===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#include "flang/Runtime/ragged.h"
10+
#include "gtest/gtest.h"
11+
12+
using namespace Fortran::runtime;
13+
14+
TEST(Ragged, RaggedArrayAllocateDeallocateTest) {
15+
struct RaggedArrayHeader header;
16+
unsigned rank = 2;
17+
int64_t *extents = new int64_t[2];
18+
extents[0] = 10;
19+
extents[1] = 100;
20+
RaggedArrayHeader *ret = (RaggedArrayHeader *)_FortranARaggedArrayAllocate(
21+
&header, false, rank, 32, extents);
22+
EXPECT_TRUE(ret != nullptr);
23+
EXPECT_TRUE(ret->bufferPointer != nullptr);
24+
EXPECT_EQ(extents, ret->extentPointer);
25+
EXPECT_EQ(10, ret->extentPointer[0]);
26+
EXPECT_EQ(100, ret->extentPointer[1]);
27+
EXPECT_EQ(rank, ret->getRank());
28+
EXPECT_FALSE(ret->isIndirection());
29+
30+
_FortranARaggedArrayDeallocate(ret);
31+
EXPECT_EQ(0u, ret->getRank());
32+
EXPECT_FALSE(ret->isIndirection());
33+
}

0 commit comments

Comments
 (0)