Skip to content

Commit 8ba9ee4

Browse files
committed
[flang] Correct the subscripts used for arguments to character intrinsics
When chasing down another unrelated bug, I noticed that the implementations of various character intrinsic functions assume that the lower bounds of (some of) their arguments were 1. This isn't necessarily the case, so I've cleaned them up, tweaked the unit tests to exercise the fix, and regularized the allocation pattern used for results to use SetBounds() before Allocate() rather than the old original Descriptor::Allocate() wrapper around CFI_allocate(). Since there were few other remaining uses of the old original Descriptor::Allocate() wrapper, I also converted them to the new one and deleted the old one. Differential Revision: https://reviews.llvm.org/D104325
1 parent 773ad55 commit 8ba9ee4

File tree

6 files changed

+66
-50
lines changed

6 files changed

+66
-50
lines changed

flang/runtime/character.cpp

Lines changed: 46 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -83,10 +83,9 @@ static void Compare(Descriptor &result, const Descriptor &x,
8383
RUNTIME_CHECK(
8484
terminator, x.rank() == y.rank() || x.rank() == 0 || y.rank() == 0);
8585
int rank{std::max(x.rank(), y.rank())};
86-
SubscriptValue lb[maxRank], ub[maxRank], xAt[maxRank], yAt[maxRank];
86+
SubscriptValue ub[maxRank], xAt[maxRank], yAt[maxRank];
8787
SubscriptValue elements{1};
8888
for (int j{0}; j < rank; ++j) {
89-
lb[j] = 1;
9089
if (x.rank() > 0 && y.rank() > 0) {
9190
SubscriptValue xUB{x.GetDimension(j).Extent()};
9291
SubscriptValue yUB{y.GetDimension(j).Extent()};
@@ -101,11 +100,15 @@ static void Compare(Descriptor &result, const Descriptor &x,
101100
ub[j] = (x.rank() ? x : y).GetDimension(j).Extent();
102101
}
103102
elements *= ub[j];
104-
xAt[j] = yAt[j] = 1;
105103
}
104+
x.GetLowerBounds(xAt);
105+
y.GetLowerBounds(yAt);
106106
result.Establish(
107107
TypeCategory::Logical, 1, nullptr, rank, ub, CFI_attribute_allocatable);
108-
if (result.Allocate(lb, ub) != CFI_SUCCESS) {
108+
for (int j{0}; j < rank; ++j) {
109+
result.GetDimension(j).SetBounds(1, ub[j]);
110+
}
111+
if (result.Allocate() != CFI_SUCCESS) {
109112
terminator.Crash("Compare: could not allocate storage for result");
110113
}
111114
std::size_t xChars{x.ElementBytes() >> shift<CHAR>};
@@ -146,18 +149,21 @@ template <typename CHAR, bool ADJUSTR>
146149
static void AdjustLRHelper(Descriptor &result, const Descriptor &string,
147150
const Terminator &terminator) {
148151
int rank{string.rank()};
149-
SubscriptValue lb[maxRank], ub[maxRank], stringAt[maxRank];
152+
SubscriptValue ub[maxRank], stringAt[maxRank];
150153
SubscriptValue elements{1};
151154
for (int j{0}; j < rank; ++j) {
152-
lb[j] = 1;
153155
ub[j] = string.GetDimension(j).Extent();
154156
elements *= ub[j];
155157
stringAt[j] = 1;
156158
}
159+
string.GetLowerBounds(stringAt);
157160
std::size_t elementBytes{string.ElementBytes()};
158161
result.Establish(string.type(), elementBytes, nullptr, rank, ub,
159162
CFI_attribute_allocatable);
160-
if (result.Allocate(lb, ub) != CFI_SUCCESS) {
163+
for (int j{0}; j < rank; ++j) {
164+
result.GetDimension(j).SetBounds(1, ub[j]);
165+
}
166+
if (result.Allocate() != CFI_SUCCESS) {
161167
terminator.Crash("ADJUSTL/R: could not allocate storage for result");
162168
}
163169
for (SubscriptValue resultAt{0}; elements-- > 0;
@@ -199,17 +205,19 @@ template <typename INT, typename CHAR>
199205
static void LenTrim(Descriptor &result, const Descriptor &string,
200206
const Terminator &terminator) {
201207
int rank{string.rank()};
202-
SubscriptValue lb[maxRank], ub[maxRank], stringAt[maxRank];
208+
SubscriptValue ub[maxRank], stringAt[maxRank];
203209
SubscriptValue elements{1};
204210
for (int j{0}; j < rank; ++j) {
205-
lb[j] = 1;
206211
ub[j] = string.GetDimension(j).Extent();
207212
elements *= ub[j];
208-
stringAt[j] = 1;
209213
}
214+
string.GetLowerBounds(stringAt);
210215
result.Establish(TypeCategory::Integer, sizeof(INT), nullptr, rank, ub,
211216
CFI_attribute_allocatable);
212-
if (result.Allocate(lb, ub) != CFI_SUCCESS) {
217+
for (int j{0}; j < rank; ++j) {
218+
result.GetDimension(j).SetBounds(1, ub[j]);
219+
}
220+
if (result.Allocate() != CFI_SUCCESS) {
213221
terminator.Crash("LEN_TRIM: could not allocate storage for result");
214222
}
215223
std::size_t stringElementChars{string.ElementBytes() >> shift<CHAR>};
@@ -370,21 +378,27 @@ static void GeneralCharFunc(Descriptor &result, const Descriptor &string,
370378
: arg.rank() ? arg.rank()
371379
: back ? back->rank()
372380
: 0};
373-
SubscriptValue lb[maxRank], ub[maxRank], stringAt[maxRank], argAt[maxRank],
381+
SubscriptValue ub[maxRank], stringAt[maxRank], argAt[maxRank],
374382
backAt[maxRank];
375383
SubscriptValue elements{1};
376384
for (int j{0}; j < rank; ++j) {
377-
lb[j] = 1;
378385
ub[j] = string.rank() ? string.GetDimension(j).Extent()
379386
: arg.rank() ? arg.GetDimension(j).Extent()
380387
: back ? back->GetDimension(j).Extent()
381388
: 1;
382389
elements *= ub[j];
383-
stringAt[j] = argAt[j] = backAt[j] = 1;
390+
}
391+
string.GetLowerBounds(stringAt);
392+
arg.GetLowerBounds(argAt);
393+
if (back) {
394+
back->GetLowerBounds(backAt);
384395
}
385396
result.Establish(TypeCategory::Integer, sizeof(INT), nullptr, rank, ub,
386397
CFI_attribute_allocatable);
387-
if (result.Allocate(lb, ub) != CFI_SUCCESS) {
398+
for (int j{0}; j < rank; ++j) {
399+
result.GetDimension(j).SetBounds(1, ub[j]);
400+
}
401+
if (result.Allocate() != CFI_SUCCESS) {
388402
terminator.Crash("SCAN/VERIFY: could not allocate storage for result");
389403
}
390404
std::size_t stringElementChars{string.ElementBytes() >> shift<CHAR>};
@@ -471,7 +485,7 @@ static void MaxMinHelper(Descriptor &accumulator, const Descriptor &x,
471485
RUNTIME_CHECK(terminator,
472486
accumulator.rank() == 0 || x.rank() == 0 ||
473487
accumulator.rank() == x.rank());
474-
SubscriptValue lb[maxRank], ub[maxRank], xAt[maxRank];
488+
SubscriptValue ub[maxRank], xAt[maxRank];
475489
SubscriptValue elements{1};
476490
std::size_t accumChars{accumulator.ElementBytes() >> shift<CHAR>};
477491
std::size_t xChars{x.ElementBytes() >> shift<CHAR>};
@@ -480,10 +494,8 @@ static void MaxMinHelper(Descriptor &accumulator, const Descriptor &x,
480494
accumChars != chars || (accumulator.rank() == 0 && x.rank() > 0)};
481495
int rank{std::max(accumulator.rank(), x.rank())};
482496
for (int j{0}; j < rank; ++j) {
483-
lb[j] = 1;
484497
if (x.rank() > 0) {
485498
ub[j] = x.GetDimension(j).Extent();
486-
xAt[j] = x.GetDimension(j).LowerBound();
487499
if (accumulator.rank() > 0) {
488500
SubscriptValue accumExt{accumulator.GetDimension(j).Extent()};
489501
if (accumExt != ub[j]) {
@@ -495,17 +507,20 @@ static void MaxMinHelper(Descriptor &accumulator, const Descriptor &x,
495507
}
496508
} else {
497509
ub[j] = accumulator.GetDimension(j).Extent();
498-
xAt[j] = 1;
499510
}
500511
elements *= ub[j];
501512
}
513+
x.GetLowerBounds(xAt);
502514
void *old{nullptr};
503515
const CHAR *accumData{accumulator.OffsetElement<CHAR>()};
504516
if (reallocate) {
505517
old = accumulator.raw().base_addr;
506518
accumulator.set_base_addr(nullptr);
507519
accumulator.raw().elem_len = chars << shift<CHAR>;
508-
RUNTIME_CHECK(terminator, accumulator.Allocate(lb, ub) == CFI_SUCCESS);
520+
for (int j{0}; j < rank; ++j) {
521+
accumulator.GetDimension(j).SetBounds(1, ub[j]);
522+
}
523+
RUNTIME_CHECK(terminator, accumulator.Allocate() == CFI_SUCCESS);
509524
}
510525
for (CHAR *result{accumulator.OffsetElement<CHAR>()}; elements-- > 0;
511526
accumData += accumChars, result += chars, x.IncrementSubscripts(xAt)) {
@@ -553,10 +568,9 @@ void RTNAME(CharacterConcatenate)(Descriptor &accumulator,
553568
accumulator.rank() == 0 || from.rank() == 0 ||
554569
accumulator.rank() == from.rank());
555570
int rank{std::max(accumulator.rank(), from.rank())};
556-
SubscriptValue lb[maxRank], ub[maxRank], fromAt[maxRank];
571+
SubscriptValue ub[maxRank], fromAt[maxRank];
557572
SubscriptValue elements{1};
558573
for (int j{0}; j < rank; ++j) {
559-
lb[j] = 1;
560574
if (accumulator.rank() > 0 && from.rank() > 0) {
561575
ub[j] = accumulator.GetDimension(j).Extent();
562576
SubscriptValue fromUB{from.GetDimension(j).Extent()};
@@ -571,20 +585,23 @@ void RTNAME(CharacterConcatenate)(Descriptor &accumulator,
571585
(accumulator.rank() ? accumulator : from).GetDimension(j).Extent();
572586
}
573587
elements *= ub[j];
574-
fromAt[j] = 1;
575588
}
576589
std::size_t oldBytes{accumulator.ElementBytes()};
577590
void *old{accumulator.raw().base_addr};
578591
accumulator.set_base_addr(nullptr);
579592
std::size_t fromBytes{from.ElementBytes()};
580593
accumulator.raw().elem_len += fromBytes;
581594
std::size_t newBytes{accumulator.ElementBytes()};
582-
if (accumulator.Allocate(lb, ub) != CFI_SUCCESS) {
595+
for (int j{0}; j < rank; ++j) {
596+
accumulator.GetDimension(j).SetBounds(1, ub[j]);
597+
}
598+
if (accumulator.Allocate() != CFI_SUCCESS) {
583599
terminator.Crash(
584600
"CharacterConcatenate: could not allocate storage for result");
585601
}
586602
const char *p{static_cast<const char *>(old)};
587603
char *to{static_cast<char *>(accumulator.raw().base_addr)};
604+
from.GetLowerBounds(fromAt);
588605
for (; elements-- > 0;
589606
to += newBytes, p += oldBytes, from.IncrementSubscripts(fromAt)) {
590607
std::memcpy(to, p, oldBytes);
@@ -601,8 +618,7 @@ void RTNAME(CharacterConcatenateScalar1)(
601618
accumulator.set_base_addr(nullptr);
602619
std::size_t oldLen{accumulator.ElementBytes()};
603620
accumulator.raw().elem_len += chars;
604-
RUNTIME_CHECK(
605-
terminator, accumulator.Allocate(nullptr, nullptr) == CFI_SUCCESS);
621+
RUNTIME_CHECK(terminator, accumulator.Allocate() == CFI_SUCCESS);
606622
std::memcpy(accumulator.OffsetElement<char>(oldLen), from, chars);
607623
FreeMemory(old);
608624
}
@@ -650,9 +666,10 @@ void RTNAME(CharacterAssign)(Descriptor &lhs, const Descriptor &rhs,
650666
for (int j{0}; j < rank; ++j) {
651667
lhsAt[j] = rhsAt[j];
652668
ub[j] = rhs.GetDimension(j).UpperBound();
669+
lhs.GetDimension(j).SetBounds(lhsAt[j], ub[j]);
653670
}
654671
}
655-
RUNTIME_CHECK(terminator, lhs.Allocate(lhsAt, ub) == CFI_SUCCESS);
672+
RUNTIME_CHECK(terminator, lhs.Allocate() == CFI_SUCCESS);
656673
}
657674
switch (lhs.raw().type) {
658675
case CFI_type_char:
@@ -941,7 +958,7 @@ void RTNAME(Repeat)(Descriptor &result, const Descriptor &string,
941958
std::size_t origBytes{string.ElementBytes()};
942959
result.Establish(string.type(), origBytes * ncopies, nullptr, 0, nullptr,
943960
CFI_attribute_allocatable);
944-
if (result.Allocate(nullptr, nullptr) != CFI_SUCCESS) {
961+
if (result.Allocate() != CFI_SUCCESS) {
945962
terminator.Crash("REPEAT could not allocate storage for result");
946963
}
947964
const char *from{string.OffsetElement()};
@@ -975,7 +992,7 @@ void RTNAME(Trim)(Descriptor &result, const Descriptor &string,
975992
}
976993
result.Establish(string.type(), resultBytes, nullptr, 0, nullptr,
977994
CFI_attribute_allocatable);
978-
RUNTIME_CHECK(terminator, result.Allocate(nullptr, nullptr) == CFI_SUCCESS);
995+
RUNTIME_CHECK(terminator, result.Allocate() == CFI_SUCCESS);
979996
std::memcpy(result.OffsetElement(), string.OffsetElement(), resultBytes);
980997
}
981998

flang/runtime/descriptor.cpp

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -148,14 +148,6 @@ int Descriptor::Allocate() {
148148
return 0;
149149
}
150150

151-
int Descriptor::Allocate(const SubscriptValue lb[], const SubscriptValue ub[]) {
152-
int result{ISO::CFI_allocate(&raw_, lb, ub, ElementBytes())};
153-
if (result == CFI_SUCCESS) {
154-
// TODO: derived type initialization
155-
}
156-
return result;
157-
}
158-
159151
int Descriptor::Deallocate(bool finalize) {
160152
Destroy(finalize);
161153
return ISO::CFI_deallocate(&raw_);

flang/runtime/descriptor.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -304,9 +304,12 @@ class Descriptor {
304304

305305
std::size_t Elements() const;
306306

307+
// Allocate() assumes Elements() and ElementBytes() work;
308+
// define the extents of the dimensions and the element length
309+
// before calling. It (re)computes the byte strides after
310+
// allocation.
307311
// TODO: SOURCE= and MOLD=
308312
int Allocate();
309-
int Allocate(const SubscriptValue lb[], const SubscriptValue ub[]);
310313
int Deallocate(bool finalize = true);
311314
void Destroy(bool finalize = true) const;
312315

flang/runtime/transformational.cpp

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -364,13 +364,11 @@ OwningPtr<Descriptor> RTNAME(Reshape)(const Descriptor &source,
364364
resultRank >= 0 && resultRank <= static_cast<SubscriptValue>(maxRank));
365365

366366
// Extract and check the shape of the result; compute its element count.
367-
SubscriptValue lowerBound[maxRank]; // all 1's
368367
SubscriptValue resultExtent[maxRank];
369368
std::size_t shapeElementBytes{shape.ElementBytes()};
370369
std::size_t resultElements{1};
371370
SubscriptValue shapeSubscript{shape.GetDimension(0).LowerBound()};
372371
for (SubscriptValue j{0}; j < resultRank; ++j, ++shapeSubscript) {
373-
lowerBound[j] = 1;
374372
resultExtent[j] = GetInt64(
375373
shape.Element<char>(&shapeSubscript), shapeElementBytes, terminator);
376374
RUNTIME_CHECK(terminator, resultExtent[j] >= 0);
@@ -434,7 +432,10 @@ OwningPtr<Descriptor> RTNAME(Reshape)(const Descriptor &source,
434432
}
435433
}
436434
// Allocate storage for the result's data.
437-
int status{result->Allocate(lowerBound, resultExtent)};
435+
for (int j{0}; j < resultRank; ++j) {
436+
result->GetDimension(j).SetBounds(1, resultExtent[j]);
437+
}
438+
int status{result->Allocate()};
438439
if (status != CFI_SUCCESS) {
439440
terminator.Crash("RESHAPE: Allocate failed (error %d)", status);
440441
}

flang/unittests/Evaluate/reshape.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ using namespace Fortran::common;
77
using namespace Fortran::runtime;
88

99
int main() {
10-
static const SubscriptValue ones[]{1, 1, 1};
1110
static const SubscriptValue sourceExtent[]{2, 3, 4};
1211
auto source{Descriptor::Create(TypeCategory::Integer, sizeof(std::int32_t),
1312
nullptr, 3, sourceExtent, CFI_attribute_allocatable)};
@@ -16,7 +15,10 @@ int main() {
1615
MATCH(sizeof(std::int32_t), source->ElementBytes());
1716
TEST(source->IsAllocatable());
1817
TEST(!source->IsPointer());
19-
TEST(source->Allocate(ones, sourceExtent) == CFI_SUCCESS);
18+
for (int j{0}; j < 3; ++j) {
19+
source->GetDimension(j).SetBounds(1, sourceExtent[j]);
20+
}
21+
TEST(source->Allocate() == CFI_SUCCESS);
2022
TEST(source->IsAllocated());
2123
MATCH(2, source->GetDimension(0).Extent());
2224
MATCH(3, source->GetDimension(1).Extent());

flang/unittests/RuntimeGTest/CharacterTest.cpp

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -30,10 +30,12 @@ OwningPtr<Descriptor> CreateDescriptor(const std::vector<SubscriptValue> &shape,
3030

3131
OwningPtr<Descriptor> descriptor{Descriptor::Create(sizeof(CHAR), length,
3232
nullptr, shape.size(), nullptr, CFI_attribute_allocatable)};
33-
if ((shape.empty() ? descriptor->Allocate()
34-
: descriptor->Allocate(
35-
std::vector<SubscriptValue>(shape.size(), 1).data(),
36-
shape.data())) != 0) {
33+
int rank{static_cast<int>(shape.size())};
34+
// Use a weird lower bound of 2 to flush out subscripting bugs
35+
for (int j{0}; j < rank; ++j) {
36+
descriptor->GetDimension(j).SetBounds(2, shape[j] + 1);
37+
}
38+
if (descriptor->Allocate() != 0) {
3739
return nullptr;
3840
}
3941

@@ -245,7 +247,7 @@ void RunExtremumTests(const char *which,
245247
ASSERT_TRUE(x->IsAllocated());
246248
ASSERT_NE(y, nullptr);
247249
ASSERT_TRUE(y->IsAllocated());
248-
function(*x, *y, /* sourceFile = */ nullptr, /* sourceLine = */ 0);
250+
function(*x, *y, __FILE__, __LINE__);
249251

250252
std::size_t length = x->ElementBytes() / sizeof(CHAR);
251253
for (std::size_t i = 0; i < t.x.size(); ++i) {
@@ -296,8 +298,7 @@ void RunAllocationTest(const char *xRaw, const char *yRaw) {
296298
ASSERT_TRUE(y->IsAllocated());
297299

298300
void *old = x->raw().base_addr;
299-
RTNAME(CharacterMin)
300-
(*x, *y, /* sourceFile = */ nullptr, /* sourceLine = */ 0);
301+
RTNAME(CharacterMin)(*x, *y, __FILE__, __LINE__);
301302
EXPECT_EQ(old, x->raw().base_addr);
302303
}
303304

0 commit comments

Comments
 (0)