[flang-commits] [flang] [flang][runtime] zero size allocation in source allocation (PR #66124)

via flang-commits flang-commits at lists.llvm.org
Wed Sep 13 03:46:45 PDT 2023


https://github.com/jeanPerier updated https://github.com/llvm/llvm-project/pull/66124:

>From b990ac3681f760dc66c1e4b7f649171788cb5571 Mon Sep 17 00:00:00 2001
From: Jean Perier <jperier at nvidia.com>
Date: Tue, 12 Sep 2023 08:06:08 -0700
Subject: [PATCH 1/2] [flang][runtime] zero size allocation in source
 allocation

Source allocation with a zero sized array is legal, and the resulting
allocatable/pointer should be allocated/associated.

The current code skipped the actual allocation, leading the allocatable
or pointer to look unallocated/disassociated.
---
 flang/runtime/allocatable.cpp           |  3 ---
 flang/runtime/pointer.cpp               |  3 ---
 flang/unittests/Runtime/Allocatable.cpp | 21 +++++++++++++++++++++
 flang/unittests/Runtime/Pointer.cpp     | 22 ++++++++++++++++++++++
 4 files changed, 43 insertions(+), 6 deletions(-)

diff --git a/flang/runtime/allocatable.cpp b/flang/runtime/allocatable.cpp
index b53440c2c3fad64..4b9e438e8a10995 100644
--- a/flang/runtime/allocatable.cpp
+++ b/flang/runtime/allocatable.cpp
@@ -168,9 +168,6 @@ int RTNAME(AllocatableAllocate)(Descriptor &descriptor, bool hasStat,
 int RTNAME(AllocatableAllocateSource)(Descriptor &alloc,
     const Descriptor &source, bool hasStat, const Descriptor *errMsg,
     const char *sourceFile, int sourceLine) {
-  if (alloc.Elements() == 0) {
-    return StatOk;
-  }
   int stat{RTNAME(AllocatableAllocate)(
       alloc, hasStat, errMsg, sourceFile, sourceLine)};
   if (stat == StatOk) {
diff --git a/flang/runtime/pointer.cpp b/flang/runtime/pointer.cpp
index 4024b78c88e33e1..0320468ffdc7904 100644
--- a/flang/runtime/pointer.cpp
+++ b/flang/runtime/pointer.cpp
@@ -154,9 +154,6 @@ int RTNAME(PointerAllocate)(Descriptor &pointer, bool hasStat,
 int RTNAME(PointerAllocateSource)(Descriptor &pointer, const Descriptor &source,
     bool hasStat, const Descriptor *errMsg, const char *sourceFile,
     int sourceLine) {
-  if (pointer.Elements() == 0) {
-    return StatOk;
-  }
   int stat{RTNAME(PointerAllocate)(
       pointer, hasStat, errMsg, sourceFile, sourceLine)};
   if (stat == StatOk) {
diff --git a/flang/unittests/Runtime/Allocatable.cpp b/flang/unittests/Runtime/Allocatable.cpp
index ed8e9193204911c..f15f26bfd9c5751 100644
--- a/flang/unittests/Runtime/Allocatable.cpp
+++ b/flang/unittests/Runtime/Allocatable.cpp
@@ -95,6 +95,27 @@ TEST(AllocatableTest, AllocateFromScalarSource) {
   a->Destroy();
 }
 
+TEST(AllocatableTest, AllocateSourceZeroSize) {
+  using Fortran::common::TypeCategory;
+  // REAL(4), ALLOCATABLE :: a(:)
+  auto a{createAllocatable(TypeCategory::Real, 4)};
+  // REAL(4) :: s(-1:-2) = 0.
+  float sourecStorage{0.F};
+  const SubscriptValue extents[1]{0};
+  auto s{Descriptor::Create(TypeCategory::Real, 4,
+      reinterpret_cast<void *>(&sourecStorage), 1, extents,
+      CFI_attribute_other)};
+  // ALLOCATE(a, SOURCE=s)
+  RTNAME(AllocatableSetBounds)(*a, 0, -1, -2);
+  RTNAME(AllocatableAllocateSource)
+  (*a, *s, /*hasStat=*/false, /*errMsg=*/nullptr, __FILE__, __LINE__);
+  EXPECT_TRUE(a->IsAllocated());
+  EXPECT_EQ(a->Elements(), 0u);
+  EXPECT_EQ(a->GetDimension(0).LowerBound(), 1);
+  EXPECT_EQ(a->GetDimension(0).UpperBound(), 0);
+  a->Destroy();
+}
+
 TEST(AllocatableTest, DoubleAllocation) {
   // CLASS(*), ALLOCATABLE :: r
   // ALLOCATE(REAL::r)
diff --git a/flang/unittests/Runtime/Pointer.cpp b/flang/unittests/Runtime/Pointer.cpp
index 09ae3c4b4d966c5..4ce13ebc50a565c 100644
--- a/flang/unittests/Runtime/Pointer.cpp
+++ b/flang/unittests/Runtime/Pointer.cpp
@@ -83,3 +83,25 @@ TEST(Pointer, AllocateFromScalarSource) {
   EXPECT_EQ(*p->OffsetElement<float>(), 3.4F);
   p->Destroy();
 }
+
+TEST(Pointer, AllocateSourceZeroSize) {
+  using Fortran::common::TypeCategory;
+  // REAL(4), POINTER :: p(:)
+  auto p{Descriptor::Create(TypeCode{Fortran::common::TypeCategory::Real, 4}, 4,
+      nullptr, 1, nullptr, CFI_attribute_pointer)};
+  // REAL(4) :: s(-1:-2) = 0.
+  float sourecStorage{0.F};
+  const SubscriptValue extents[1]{0};
+  auto s{Descriptor::Create(TypeCategory::Real, 4,
+      reinterpret_cast<void *>(&sourecStorage), 1, extents,
+      CFI_attribute_other)};
+  // ALLOCATE(p, SOURCE=s)
+  RTNAME(PointerSetBounds)(*p, 0, -1, -2);
+  RTNAME(PointerAllocateSource)
+  (*p, *s, /*hasStat=*/false, /*errMsg=*/nullptr, __FILE__, __LINE__);
+  EXPECT_TRUE(RTNAME(PointerIsAssociated)(*p));
+  EXPECT_EQ(p->Elements(), 0u);
+  EXPECT_EQ(p->GetDimension(0).LowerBound(), 1);
+  EXPECT_EQ(p->GetDimension(0).UpperBound(), 0);
+  p->Destroy();
+}

>From 7c23521ed93705719d585d9d3736188f004abd52 Mon Sep 17 00:00:00 2001
From: Jean Perier <jperier at nvidia.com>
Date: Wed, 13 Sep 2023 02:51:01 -0700
Subject: [PATCH 2/2] Update Descriptor::Allocate to always allocate at least
 one byte

---
 flang/runtime/descriptor.cpp | 7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/flang/runtime/descriptor.cpp b/flang/runtime/descriptor.cpp
index 1964a6798776b1b..ab6460708e9b68f 100644
--- a/flang/runtime/descriptor.cpp
+++ b/flang/runtime/descriptor.cpp
@@ -142,8 +142,11 @@ std::size_t Descriptor::Elements() const {
 
 int Descriptor::Allocate() {
   std::size_t byteSize{Elements() * ElementBytes()};
-  void *p{std::malloc(byteSize)};
-  if (!p && byteSize) {
+  // Zero size allocation is possible in Fortran and the resulting
+  // descriptor must be allocated/associated. Since std::malloc(0)
+  // result is implementation defined, always allocate at least one byte.
+  void *p{byteSize ? std::malloc(byteSize) : std::malloc(1)};
+  if (!p) {
     return CFI_ERROR_MEM_ALLOCATION;
   }
   // TODO: image synchronization



More information about the flang-commits mailing list