Skip to content

Commit 3b61587

Browse files
committed
[flang] LBOUND() edge case: empty dimension
LBOUND must return 1 for an empty dimension, no matter what explicit expression might appear in a declaration or arrive in a descriptor. Differential Revision: https://reviews.llvm.org/D121488
1 parent c2e7e75 commit 3b61587

File tree

13 files changed

+229
-137
lines changed

13 files changed

+229
-137
lines changed

flang/docs/Extensions.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,10 @@ end
7171
In common with some other compilers, the clock is in milliseconds
7272
for kinds <= 4 and nanoseconds otherwise where the target system
7373
supports these rates.
74+
* If a dimension of a descriptor has zero extent in a call to
75+
`CFI_section`, `CFI_setpointer` or `CFI_allocate`, the lower
76+
bound on that dimension will be set to 1 for consistency with
77+
the `LBOUND()` intrinsic function.
7478

7579
## Extensions, deletions, and legacy features supported by default
7680

flang/include/flang/Evaluate/shape.h

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -62,16 +62,27 @@ template <typename A> std::optional<Shape> GetShape(const A &);
6262

6363
// The dimension argument to these inquiries is zero-based,
6464
// unlike the DIM= arguments to many intrinsics.
65-
ExtentExpr GetLowerBound(const NamedEntity &, int dimension);
66-
ExtentExpr GetLowerBound(FoldingContext &, const NamedEntity &, int dimension);
65+
//
66+
// GetRawLowerBound() returns a lower bound expression, which may
67+
// not be suitable for all purposes; specifically, it might not be invariant
68+
// in its scope, and it will not have been forced to 1 on an empty dimension.
69+
// GetLBOUND()'s result is safer, but it is optional because it does fail
70+
// in those circumstances.
71+
ExtentExpr GetRawLowerBound(const NamedEntity &, int dimension);
72+
ExtentExpr GetRawLowerBound(
73+
FoldingContext &, const NamedEntity &, int dimension);
74+
MaybeExtentExpr GetLBOUND(const NamedEntity &, int dimension);
75+
MaybeExtentExpr GetLBOUND(FoldingContext &, const NamedEntity &, int dimension);
6776
MaybeExtentExpr GetUpperBound(const NamedEntity &, int dimension);
6877
MaybeExtentExpr GetUpperBound(
6978
FoldingContext &, const NamedEntity &, int dimension);
7079
MaybeExtentExpr ComputeUpperBound(ExtentExpr &&lower, MaybeExtentExpr &&extent);
7180
MaybeExtentExpr ComputeUpperBound(
7281
FoldingContext &, ExtentExpr &&lower, MaybeExtentExpr &&extent);
73-
Shape GetLowerBounds(const NamedEntity &);
74-
Shape GetLowerBounds(FoldingContext &, const NamedEntity &);
82+
Shape GetRawLowerBounds(const NamedEntity &);
83+
Shape GetRawLowerBounds(FoldingContext &, const NamedEntity &);
84+
Shape GetLBOUNDs(const NamedEntity &);
85+
Shape GetLBOUNDs(FoldingContext &, const NamedEntity &);
7586
Shape GetUpperBounds(const NamedEntity &);
7687
Shape GetUpperBounds(FoldingContext &, const NamedEntity &);
7788
MaybeExtentExpr GetExtent(const NamedEntity &, int dimension);

flang/include/flang/Runtime/descriptor.h

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,10 +50,17 @@ class Dimension {
5050
SubscriptValue ByteStride() const { return raw_.sm; }
5151

5252
Dimension &SetBounds(SubscriptValue lower, SubscriptValue upper) {
53-
raw_.lower_bound = lower;
54-
raw_.extent = upper >= lower ? upper - lower + 1 : 0;
53+
if (upper >= lower) {
54+
raw_.lower_bound = lower;
55+
raw_.extent = upper - lower + 1;
56+
} else {
57+
raw_.lower_bound = 1;
58+
raw_.extent = 0;
59+
}
5560
return *this;
5661
}
62+
// Do not use this API to cause the LB of an empty dimension
63+
// to anything other than 1. Use SetBounds() instead if you can.
5764
Dimension &SetLowerBound(SubscriptValue lower) {
5865
raw_.lower_bound = lower;
5966
return *this;

flang/lib/Evaluate/check-expression.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ bool IsConstantExprHelper<INVARIANT>::operator()(
120120
} else if (intrinsic->name == "lbound" && call.arguments().size() == 1) {
121121
// LBOUND(x) without DIM=
122122
auto base{ExtractNamedEntity(call.arguments()[0]->UnwrapExpr())};
123-
return base && IsConstantExprShape(GetLowerBounds(*base));
123+
return base && IsConstantExprShape(GetLBOUNDs(*base));
124124
} else if (intrinsic->name == "ubound" && call.arguments().size() == 1) {
125125
// UBOUND(x) without DIM=
126126
auto base{ExtractNamedEntity(call.arguments()[0]->UnwrapExpr())};
@@ -434,7 +434,7 @@ std::optional<Expr<SomeType>> NonPointerInitializationExpr(const Symbol &symbol,
434434
// expand the scalar constant to an array
435435
return ScalarConstantExpander{std::move(*extents),
436436
AsConstantExtents(
437-
context, GetLowerBounds(context, NamedEntity{symbol}))}
437+
context, GetRawLowerBounds(context, NamedEntity{symbol}))}
438438
.Expand(std::move(folded));
439439
} else if (auto resultShape{GetShape(context, folded)}) {
440440
if (CheckConformance(context.messages(), symTS->shape(),
@@ -443,8 +443,8 @@ std::optional<Expr<SomeType>> NonPointerInitializationExpr(const Symbol &symbol,
443443
.value_or(false /*fail if not known now to conform*/)) {
444444
// make a constant array with adjusted lower bounds
445445
return ArrayConstantBoundChanger{
446-
std::move(*AsConstantExtents(
447-
context, GetLowerBounds(context, NamedEntity{symbol})))}
446+
std::move(*AsConstantExtents(context,
447+
GetRawLowerBounds(context, NamedEntity{symbol})))}
448448
.ChangeLbounds(std::move(folded));
449449
}
450450
}

flang/lib/Evaluate/constant.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,11 @@ ConstantBounds::~ConstantBounds() = default;
2525
void ConstantBounds::set_lbounds(ConstantSubscripts &&lb) {
2626
CHECK(lb.size() == shape_.size());
2727
lbounds_ = std::move(lb);
28+
for (std::size_t j{0}; j < shape_.size(); ++j) {
29+
if (shape_[j] == 0) {
30+
lbounds_[j] = 1;
31+
}
32+
}
2833
}
2934

3035
void ConstantBounds::SetLowerBoundsToOne() {

flang/lib/Evaluate/fold-designator.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ std::optional<OffsetSymbol> DesignatorFolder::FoldDesignator(
5050
if (auto type{DynamicType::From(array)}) {
5151
if (auto extents{GetConstantExtents(context_, array)}) {
5252
if (auto bytes{ToInt64(type->MeasureSizeInBytes(context_, true))}) {
53-
Shape lbs{GetLowerBounds(context_, x.base())};
53+
Shape lbs{GetLBOUNDs(context_, x.base())};
5454
if (auto lowerBounds{AsConstantExtents(context_, lbs)}) {
5555
std::optional<OffsetSymbol> result;
5656
if (!x.base().IsSymbol() &&
@@ -206,7 +206,7 @@ static std::optional<ArrayRef> OffsetToArrayRef(FoldingContext &context,
206206
NamedEntity &&entity, const Shape &shape, const DynamicType &elementType,
207207
ConstantSubscript &offset) {
208208
auto extents{AsConstantExtents(context, shape)};
209-
Shape lbs{GetLowerBounds(context, entity)};
209+
Shape lbs{GetRawLowerBounds(context, entity)};
210210
auto lower{AsConstantExtents(context, lbs)};
211211
auto elementBytes{ToInt64(elementType.MeasureSizeInBytes(context, true))};
212212
if (!extents || !lower || !elementBytes || *elementBytes <= 0) {

flang/lib/Evaluate/fold-integer.cpp

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -76,10 +76,11 @@ Expr<Type<TypeCategory::Integer, KIND>> LBOUND(FoldingContext &context,
7676
if (symbol.Rank() == rank) {
7777
lowerBoundsAreOne = false;
7878
if (dim) {
79-
return Fold(context,
80-
ConvertToType<T>(GetLowerBound(context, *named, *dim)));
79+
if (auto lb{GetLBOUND(context, *named, *dim)}) {
80+
return Fold(context, ConvertToType<T>(std::move(*lb)));
81+
}
8182
} else if (auto extents{
82-
AsExtentArrayExpr(GetLowerBounds(context, *named))}) {
83+
AsExtentArrayExpr(GetLBOUNDs(context, *named))}) {
8384
return Fold(context,
8485
ConvertToType<T>(Expr<ExtentType>{std::move(*extents)}));
8586
}

flang/lib/Evaluate/fold.cpp

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -36,12 +36,13 @@ std::optional<Constant<SubscriptInteger>> GetConstantSubscript(
3636
auto lower{triplet.lower()}, upper{triplet.upper()};
3737
std::optional<ConstantSubscript> stride{ToInt64(triplet.stride())};
3838
if (!lower) {
39-
lower = GetLowerBound(context, base, dim);
39+
lower = GetLBOUND(context, base, dim);
4040
}
4141
if (!upper) {
42-
upper =
43-
ComputeUpperBound(context, GetLowerBound(context, base, dim),
44-
GetExtent(context, base, dim));
42+
if (auto lb{GetLBOUND(context, base, dim)}) {
43+
upper = ComputeUpperBound(
44+
context, std::move(*lb), GetExtent(context, base, dim));
45+
}
4546
}
4647
auto lbi{ToInt64(lower)}, ubi{ToInt64(upper)};
4748
if (lbi && ubi && stride && *stride != 0) {

0 commit comments

Comments
 (0)