Skip to content

Commit 2b78c64

Browse files
authored
[flang] add API to copy and update descriptors for assumed ranks (#93305)
When passing assumed-rank around, the lower bounds, dynamic type and attribute must sometimes be updated to match the dummy attributes. See https://github.com/llvm/llvm-project/blob/main/flang/docs/AssumedRank.md#annex-1---descriptor-temporary-for-the-dummy-arguments for more details. Doing it inline would require generating many instructions and block CFG at the LLVM IR dialect level in codegen. Go for a simple runtime API instead. A matching fir.rebox_assumed_rank operation will be created and will allow for easier future optimizations when inlining is done in FIR.
1 parent 7429950 commit 2b78c64

File tree

4 files changed

+100
-0
lines changed

4 files changed

+100
-0
lines changed

flang/include/flang/Runtime/support.h

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#ifndef FORTRAN_RUNTIME_SUPPORT_H_
1111
#define FORTRAN_RUNTIME_SUPPORT_H_
1212

13+
#include "flang/ISO_Fortran_binding_wrapper.h"
1314
#include "flang/Runtime/entry-names.h"
1415
#include <cstddef>
1516
#include <cstdint>
@@ -18,11 +19,29 @@ namespace Fortran::runtime {
1819

1920
class Descriptor;
2021

22+
namespace typeInfo {
23+
class DerivedType;
24+
}
25+
26+
enum class LowerBoundModifier : int {
27+
Preserve = 0,
28+
SetToOnes = 1,
29+
SetToZeroes = 2
30+
};
31+
2132
extern "C" {
2233

2334
// Predicate: is the storage described by a Descriptor contiguous in memory?
2435
bool RTDECL(IsContiguous)(const Descriptor &);
2536

37+
// Copy "from" descriptor into "to" descriptor and update "to" dynamic type,
38+
// CFI_attribute, and lower bounds according to the other arguments.
39+
// "newDynamicType" may be a null pointer in which case "to" dynamic type is the
40+
// one of "from".
41+
void RTDECL(CopyAndUpdateDescriptor)(Descriptor &to, const Descriptor &from,
42+
const typeInfo::DerivedType *newDynamicType,
43+
ISO::CFI_attribute_t newAttribute, enum LowerBoundModifier newLowerBounds);
44+
2645
} // extern "C"
2746
} // namespace Fortran::runtime
2847
#endif // FORTRAN_RUNTIME_SUPPORT_H_

flang/runtime/support.cpp

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
//===----------------------------------------------------------------------===//
88

99
#include "flang/Runtime/support.h"
10+
#include "type-info.h"
1011
#include "flang/Runtime/descriptor.h"
1112

1213
namespace Fortran::runtime {
@@ -17,6 +18,27 @@ bool RTDEF(IsContiguous)(const Descriptor &descriptor) {
1718
return descriptor.IsContiguous();
1819
}
1920

21+
void RTDEF(CopyAndUpdateDescriptor)(Descriptor &to, const Descriptor &from,
22+
const typeInfo::DerivedType *newDynamicType,
23+
ISO::CFI_attribute_t newAttribute, enum LowerBoundModifier newLowerBounds) {
24+
to = from;
25+
if (newDynamicType) {
26+
DescriptorAddendum *toAddendum{to.Addendum()};
27+
INTERNAL_CHECK(toAddendum);
28+
toAddendum->set_derivedType(newDynamicType);
29+
to.raw().elem_len = newDynamicType->sizeInBytes();
30+
}
31+
to.raw().attribute = newAttribute;
32+
if (newLowerBounds != LowerBoundModifier::Preserve) {
33+
const ISO::CFI_index_t newLowerBound{
34+
newLowerBounds == LowerBoundModifier::SetToOnes ? 1 : 0};
35+
const int rank{to.rank()};
36+
for (int i = 0; i < rank; ++i) {
37+
to.GetDimension(i).SetLowerBound(newLowerBound);
38+
}
39+
}
40+
}
41+
2042
RT_EXT_API_GROUP_END
2143
} // extern "C"
2244
} // namespace Fortran::runtime

flang/unittests/Runtime/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ add_flang_unittest(FlangRuntimeTests
2525
Reduction.cpp
2626
RuntimeCrashTest.cpp
2727
Stop.cpp
28+
Support.cpp
2829
Time.cpp
2930
TemporaryStack.cpp
3031
Transformational.cpp

flang/unittests/Runtime/Support.cpp

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
//===-- flang/unittests/Runtime/Support.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/support.h"
10+
#include "gtest/gtest.h"
11+
#include "tools.h"
12+
#include "flang/Runtime/descriptor.h"
13+
14+
using namespace Fortran::runtime;
15+
using Fortran::common::TypeCategory;
16+
TEST(CopyAndUpdateDescriptor, Basic) {
17+
auto x{MakeArray<TypeCategory::Integer, 4>(
18+
std::vector<int>{2, 3}, std::vector<std::int32_t>{0, 1, 2, 3, 4, 5})};
19+
x->GetDimension(0).SetLowerBound(11);
20+
x->GetDimension(1).SetLowerBound(12);
21+
22+
StaticDescriptor<2, false> statDesc;
23+
Descriptor &result{statDesc.descriptor()};
24+
25+
RTNAME(CopyAndUpdateDescriptor)
26+
(result, *x, nullptr, CFI_attribute_pointer, LowerBoundModifier::Preserve);
27+
ASSERT_EQ(result.rank(), 2);
28+
EXPECT_EQ(result.raw().base_addr, x->raw().base_addr);
29+
EXPECT_TRUE(result.IsPointer());
30+
EXPECT_EQ(result.GetDimension(0).Extent(), x->GetDimension(0).Extent());
31+
EXPECT_EQ(
32+
result.GetDimension(0).LowerBound(), x->GetDimension(0).LowerBound());
33+
EXPECT_EQ(result.GetDimension(1).Extent(), x->GetDimension(1).Extent());
34+
EXPECT_EQ(
35+
result.GetDimension(1).LowerBound(), x->GetDimension(1).LowerBound());
36+
37+
RTNAME(CopyAndUpdateDescriptor)
38+
(result, *x, nullptr, CFI_attribute_allocatable,
39+
LowerBoundModifier::SetToZeroes);
40+
ASSERT_EQ(result.rank(), 2);
41+
EXPECT_EQ(result.raw().base_addr, x->raw().base_addr);
42+
EXPECT_TRUE(result.IsAllocatable());
43+
EXPECT_EQ(result.GetDimension(0).Extent(), x->GetDimension(0).Extent());
44+
EXPECT_EQ(result.GetDimension(0).LowerBound(), 0);
45+
EXPECT_EQ(result.GetDimension(1).Extent(), x->GetDimension(1).Extent());
46+
EXPECT_EQ(result.GetDimension(1).LowerBound(), 0);
47+
48+
RTNAME(CopyAndUpdateDescriptor)
49+
(result, *x, nullptr, CFI_attribute_other, LowerBoundModifier::SetToOnes);
50+
ASSERT_EQ(result.rank(), 2);
51+
EXPECT_EQ(result.raw().base_addr, x->raw().base_addr);
52+
EXPECT_FALSE(result.IsAllocatable());
53+
EXPECT_FALSE(result.IsPointer());
54+
EXPECT_EQ(result.GetDimension(0).Extent(), x->GetDimension(0).Extent());
55+
EXPECT_EQ(result.GetDimension(0).LowerBound(), 1);
56+
EXPECT_EQ(result.GetDimension(1).Extent(), x->GetDimension(1).Extent());
57+
EXPECT_EQ(result.GetDimension(1).LowerBound(), 1);
58+
}

0 commit comments

Comments
 (0)