Skip to content

Commit 92e5234

Browse files
committed
[flang][hlfir] Lower evaluate::DescriptorInquiry
Lower extents and lower bounds inquiries with a compile time constant DIM that cannot be folded by the front-end. Differential Revision: https://reviews.llvm.org/D143476
1 parent f634096 commit 92e5234

File tree

4 files changed

+186
-31
lines changed

4 files changed

+186
-31
lines changed

flang/include/flang/Optimizer/Builder/HLFIRTools.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -280,6 +280,16 @@ genBounds(mlir::Location loc, fir::FirOpBuilder &builder, mlir::Value shape);
280280
mlir::Value genShape(mlir::Location loc, fir::FirOpBuilder &builder,
281281
Entity entity);
282282

283+
/// Compute the extent of \p entity in dimension \p dim. Crashes
284+
/// if dim is bigger than the entity's rank.
285+
mlir::Value genExtent(mlir::Location loc, fir::FirOpBuilder &builder,
286+
hlfir::Entity entity, unsigned dim);
287+
288+
/// Compute the lower bound of \p entity in dimension \p dim. Crashes
289+
/// if dim is bigger than the entity's rank.
290+
mlir::Value genLBound(mlir::Location loc, fir::FirOpBuilder &builder,
291+
hlfir::Entity entity, unsigned dim);
292+
283293
/// Generate a vector of extents with index type from a fir.shape
284294
/// of fir.shape_shift value.
285295
llvm::SmallVector<mlir::Value> getIndexExtents(mlir::Location loc,

flang/lib/Lower/ConvertExprToHLFIR.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1189,9 +1189,11 @@ class HlfirBuilder {
11891189
case Fortran::evaluate::DescriptorInquiry::Field::Len:
11901190
return castResult(hlfir::genCharLength(loc, builder, entity));
11911191
case Fortran::evaluate::DescriptorInquiry::Field::LowerBound:
1192-
TODO(loc, "lower bound inquiry in HLFIR");
1192+
return castResult(
1193+
hlfir::genLBound(loc, builder, entity, desc.dimension()));
11931194
case Fortran::evaluate::DescriptorInquiry::Field::Extent:
1194-
TODO(loc, "extent inquiry in HLFIR");
1195+
return castResult(
1196+
hlfir::genExtent(loc, builder, entity, desc.dimension()));
11951197
case Fortran::evaluate::DescriptorInquiry::Field::Rank:
11961198
TODO(loc, "rank inquiry on assumed rank");
11971199
case Fortran::evaluate::DescriptorInquiry::Field::Stride:

flang/lib/Optimizer/Builder/HLFIRTools.cpp

Lines changed: 87 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -399,7 +399,7 @@ hlfir::genBounds(mlir::Location loc, fir::FirOpBuilder &builder,
399399
return result;
400400
}
401401

402-
static hlfir::Entity followEntitySource(hlfir::Entity entity) {
402+
static hlfir::Entity followShapeInducingSource(hlfir::Entity entity) {
403403
while (true) {
404404
if (auto reassoc = entity.getDefiningOp<hlfir::NoReassocOp>()) {
405405
entity = hlfir::Entity{reassoc.getVal()};
@@ -414,6 +414,24 @@ static hlfir::Entity followEntitySource(hlfir::Entity entity) {
414414
return entity;
415415
}
416416

417+
static mlir::Value computeVariableExtent(mlir::Location loc,
418+
fir::FirOpBuilder &builder,
419+
hlfir::Entity variable,
420+
fir::SequenceType seqTy,
421+
unsigned dim) {
422+
mlir::Type idxTy = builder.getIndexType();
423+
if (seqTy.getShape().size() > dim) {
424+
fir::SequenceType::Extent typeExtent = seqTy.getShape()[dim];
425+
if (typeExtent != fir::SequenceType::getUnknownExtent())
426+
return builder.createIntegerConstant(loc, idxTy, typeExtent);
427+
}
428+
assert(variable.getType().isa<fir::BaseBoxType>() &&
429+
"array variable with dynamic extent must be boxed");
430+
mlir::Value dimVal = builder.createIntegerConstant(loc, idxTy, dim);
431+
auto dimInfo = builder.create<fir::BoxDimsOp>(loc, idxTy, idxTy, idxTy,
432+
variable, dimVal);
433+
return dimInfo.getExtent();
434+
}
417435
llvm::SmallVector<mlir::Value> getVariableExtents(mlir::Location loc,
418436
fir::FirOpBuilder &builder,
419437
hlfir::Entity variable) {
@@ -432,42 +450,38 @@ llvm::SmallVector<mlir::Value> getVariableExtents(mlir::Location loc,
432450
fir::SequenceType seqTy =
433451
hlfir::getFortranElementOrSequenceType(variable.getType())
434452
.cast<fir::SequenceType>();
435-
mlir::Type idxTy = builder.getIndexType();
436-
for (auto typeExtent : seqTy.getShape())
437-
if (typeExtent != fir::SequenceType::getUnknownExtent()) {
438-
extents.push_back(builder.createIntegerConstant(loc, idxTy, typeExtent));
439-
} else {
440-
assert(variable.getType().isa<fir::BaseBoxType>() &&
441-
"array variable with dynamic extent must be boxed");
442-
mlir::Value dim =
443-
builder.createIntegerConstant(loc, idxTy, extents.size());
444-
auto dimInfo = builder.create<fir::BoxDimsOp>(loc, idxTy, idxTy, idxTy,
445-
variable, dim);
446-
extents.push_back(dimInfo.getExtent());
447-
}
453+
unsigned rank = seqTy.getShape().size();
454+
for (unsigned dim = 0; dim < rank; ++dim)
455+
extents.push_back(
456+
computeVariableExtent(loc, builder, variable, seqTy, dim));
448457
return extents;
449458
}
450459

451-
mlir::Value hlfir::genShape(mlir::Location loc, fir::FirOpBuilder &builder,
452-
hlfir::Entity entity) {
453-
assert(entity.isArray() && "entity must be an array");
454-
entity = followEntitySource(entity);
455-
460+
static mlir::Value tryRetrievingShapeOrShift(hlfir::Entity entity) {
456461
if (entity.getType().isa<hlfir::ExprType>()) {
457462
if (auto elemental = entity.getDefiningOp<hlfir::ElementalOp>())
458463
return elemental.getShape();
459-
TODO(loc, "get shape from HLFIR expr without producer holding the shape");
464+
return mlir::Value{};
460465
}
461-
// Entity is an array variable.
462-
if (auto varIface = entity.getIfVariableInterface()) {
463-
if (auto shape = varIface.getShape()) {
464-
if (shape.getType().isa<fir::ShapeType>())
465-
return shape;
466-
if (shape.getType().isa<fir::ShapeShiftType>())
467-
if (auto s = shape.getDefiningOp<fir::ShapeShiftOp>())
468-
return builder.create<fir::ShapeOp>(loc, s.getExtents());
469-
}
466+
if (auto varIface = entity.getIfVariableInterface())
467+
return varIface.getShape();
468+
return {};
469+
}
470+
471+
mlir::Value hlfir::genShape(mlir::Location loc, fir::FirOpBuilder &builder,
472+
hlfir::Entity entity) {
473+
assert(entity.isArray() && "entity must be an array");
474+
entity = followShapeInducingSource(entity);
475+
assert(entity && "what?");
476+
if (auto shape = tryRetrievingShapeOrShift(entity)) {
477+
if (shape.getType().isa<fir::ShapeType>())
478+
return shape;
479+
if (shape.getType().isa<fir::ShapeShiftType>())
480+
if (auto s = shape.getDefiningOp<fir::ShapeShiftOp>())
481+
return builder.create<fir::ShapeOp>(loc, s.getExtents());
470482
}
483+
if (entity.getType().isa<hlfir::ExprType>())
484+
TODO(loc, "get shape from HLFIR expr without producer holding the shape");
471485
// There is no shape lying around for this entity. Retrieve the extents and
472486
// build a new fir.shape.
473487
return builder.create<fir::ShapeOp>(loc,
@@ -484,6 +498,50 @@ hlfir::getIndexExtents(mlir::Location loc, fir::FirOpBuilder &builder,
484498
return extents;
485499
}
486500

501+
mlir::Value hlfir::genExtent(mlir::Location loc, fir::FirOpBuilder &builder,
502+
hlfir::Entity entity, unsigned dim) {
503+
entity = followShapeInducingSource(entity);
504+
if (auto shape = tryRetrievingShapeOrShift(entity)) {
505+
auto extents = getExplicitExtentsFromShape(shape);
506+
if (!extents.empty()) {
507+
assert(extents.size() > dim && "bad inquiry");
508+
return extents[dim];
509+
}
510+
}
511+
if (entity.isVariable()) {
512+
if (entity.isMutableBox())
513+
entity = hlfir::derefPointersAndAllocatables(loc, builder, entity);
514+
// Use the type shape information, and/or the fir.box/fir.class shape
515+
// information if any extents are not static.
516+
fir::SequenceType seqTy =
517+
hlfir::getFortranElementOrSequenceType(entity.getType())
518+
.cast<fir::SequenceType>();
519+
return computeVariableExtent(loc, builder, entity, seqTy, dim);
520+
}
521+
TODO(loc, "get extent from HLFIR expr without producer holding the shape");
522+
}
523+
524+
mlir::Value hlfir::genLBound(mlir::Location loc, fir::FirOpBuilder &builder,
525+
hlfir::Entity entity, unsigned dim) {
526+
if (!entity.hasNonDefaultLowerBounds())
527+
return builder.createIntegerConstant(loc, builder.getIndexType(), 1);
528+
if (auto shape = tryRetrievingShapeOrShift(entity)) {
529+
auto lbounds = getExplicitLboundsFromShape(shape);
530+
if (!lbounds.empty()) {
531+
assert(lbounds.size() > dim && "bad inquiry");
532+
return lbounds[dim];
533+
}
534+
}
535+
if (entity.isMutableBox())
536+
entity = hlfir::derefPointersAndAllocatables(loc, builder, entity);
537+
assert(entity.getType().isa<fir::BaseBoxType>() && "must be a box");
538+
mlir::Type idxTy = builder.getIndexType();
539+
mlir::Value dimVal = builder.createIntegerConstant(loc, idxTy, dim);
540+
auto dimInfo =
541+
builder.create<fir::BoxDimsOp>(loc, idxTy, idxTy, idxTy, entity, dimVal);
542+
return dimInfo.getLowerBound();
543+
}
544+
487545
void hlfir::genLengthParameters(mlir::Location loc, fir::FirOpBuilder &builder,
488546
Entity entity,
489547
llvm::SmallVectorImpl<mlir::Value> &result) {
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
! Test lowering of extent and lower bound inquires that
2+
! come in lowering as evaluate::DescriptorInquiry.
3+
4+
! RUN: bbc -emit-fir -hlfir -o - %s | FileCheck %s
5+
6+
subroutine test_assumed_shape(x, r)
7+
integer(8) :: r
8+
real :: x(:,:)
9+
r = size(x, dim=2, kind=8)
10+
end subroutine
11+
! CHECK-LABEL: func.func @_QPtest_assumed_shape(
12+
! CHECK: %[[VAL_3:.*]]:2 = hlfir.declare {{.*}}Ex
13+
! CHECK: %[[VAL_4:.*]] = arith.constant 1 : index
14+
! CHECK: %[[VAL_5:.*]]:3 = fir.box_dims %[[VAL_3]]#0, %[[VAL_4]] : (!fir.box<!fir.array<?x?xf32>>, index) -> (index, index, index)
15+
! CHECK: %[[VAL_6:.*]] = fir.convert %[[VAL_5]]#1 : (index) -> i64
16+
! CHECK: hlfir.assign %[[VAL_6]] to %{{.*}}
17+
18+
subroutine test_explicit_shape(x, n, m, r)
19+
integer(8) :: n, m, r
20+
real :: x(n,m)
21+
r = size(x, dim=2, kind=8)
22+
end subroutine
23+
! CHECK-LABEL: func.func @_QPtest_explicit_shape(
24+
! CHECK: %[[VAL_17:.*]] = fir.shape %{{.*}}, %[[VAL_16:.*]] : (index, index) -> !fir.shape<2>
25+
! CHECK: %[[VAL_18:.*]]:2 = hlfir.declare %{{.*}}(%[[VAL_17]]) {{.*}}Ex
26+
! CHECK: %[[VAL_19:.*]] = fir.convert %[[VAL_16]] : (index) -> i64
27+
! CHECK: hlfir.assign %[[VAL_19]] to %{{.*}}
28+
29+
subroutine test_pointer(x, r)
30+
integer(8) :: r
31+
real :: x(:,:)
32+
r = size(x, dim=2, kind=8)
33+
end subroutine
34+
! CHECK-LABEL: func.func @_QPtest_pointer(
35+
! CHECK: %[[VAL_3:.*]]:2 = hlfir.declare {{.*}}Ex
36+
! CHECK: %[[VAL_4:.*]] = arith.constant 1 : index
37+
! CHECK: %[[VAL_5:.*]]:3 = fir.box_dims %[[VAL_3]]#0, %[[VAL_4]] : (!fir.box<!fir.array<?x?xf32>>, index) -> (index, index, index)
38+
! CHECK: %[[VAL_6:.*]] = fir.convert %[[VAL_5]]#1 : (index) -> i64
39+
! CHECK: hlfir.assign %[[VAL_6]] to %{{.*}}
40+
41+
subroutine test_lbound_assumed_shape(x, l1, l2, r)
42+
integer(8) :: l1, l2, r
43+
real :: x(l1:,l2:)
44+
r = lbound(x, dim=2, kind=8)
45+
end subroutine
46+
! CHECK: %[[VAL_11:.*]] = fir.shift %[[VAL_8:.*]], %[[VAL_10:.*]] : (index, index) -> !fir.shift<2>
47+
! CHECK: %[[VAL_12:.*]]:2 = hlfir.declare %{{.*}}(%[[VAL_11]]) {{.*}}Ex
48+
! CHECK: %[[VAL_13:.*]] = arith.constant 1 : i64
49+
! CHECK: %[[VAL_14:.*]] = arith.constant 0 : index
50+
! CHECK: %[[VAL_15:.*]] = arith.constant 1 : index
51+
! CHECK: %[[VAL_16:.*]]:3 = fir.box_dims %[[VAL_12]]#1, %[[VAL_15]] : (!fir.box<!fir.array<?x?xf32>>, index) -> (index, index, index)
52+
! CHECK: %[[VAL_17:.*]] = arith.cmpi eq, %[[VAL_16]]#1, %[[VAL_14]] : index
53+
! CHECK: %[[VAL_18:.*]] = fir.convert %[[VAL_13]] : (i64) -> index
54+
! CHECK: %[[VAL_19:.*]] = arith.select %[[VAL_17]], %[[VAL_18]], %[[VAL_10]] : index
55+
! CHECK: %[[VAL_20:.*]] = fir.convert %[[VAL_19]] : (index) -> i64
56+
! CHECK: hlfir.assign %[[VAL_20]] to %{{.*}}
57+
58+
subroutine test_lbound_explicit_shape(x, n, m, l1, l2, r)
59+
integer(8) :: n, m, l1, l2, r
60+
real :: x(l1:n,l2:m)
61+
r = lbound(x, dim=2, kind=8)
62+
end subroutine
63+
! CHECK-LABEL: func.func @_QPtest_lbound_explicit_shape(
64+
! CHECK: %[[VAL_31:.*]] = fir.shape_shift %{{.*}}, %{{.*}}, %[[VAL_22:.*]], %[[VAL_30:.*]] : (index, index, index, index) -> !fir.shapeshift<2>
65+
! CHECK: %[[VAL_32:.*]]:2 = hlfir.declare %{{.*}}(%[[VAL_31]]) {{.*}}Ex
66+
! CHECK: %[[VAL_33:.*]] = arith.constant 1 : i64
67+
! CHECK: %[[VAL_34:.*]] = arith.constant 0 : index
68+
! CHECK: %[[VAL_35:.*]] = arith.cmpi eq, %[[VAL_30]], %[[VAL_34]] : index
69+
! CHECK: %[[VAL_36:.*]] = fir.convert %[[VAL_33]] : (i64) -> index
70+
! CHECK: %[[VAL_37:.*]] = arith.select %[[VAL_35]], %[[VAL_36]], %[[VAL_22]] : index
71+
! CHECK: %[[VAL_38:.*]] = fir.convert %[[VAL_37]] : (index) -> i64
72+
! CHECK: hlfir.assign %[[VAL_38]] to %{{.*}}
73+
74+
subroutine test_lbound_pointer(x, r)
75+
integer(8) :: r
76+
real, pointer :: x(:,:)
77+
r = lbound(x, dim=2, kind=8)
78+
end subroutine
79+
! CHECK-LABEL: func.func @_QPtest_lbound_pointer(
80+
! CHECK: %[[VAL_3:.*]]:2 = hlfir.declare {{.*}}Ex
81+
! CHECK: %[[VAL_4:.*]] = fir.load %[[VAL_3]]#0 : !fir.ref<!fir.box<!fir.ptr<!fir.array<?x?xf32>>>>
82+
! CHECK: %[[VAL_5:.*]] = arith.constant 1 : index
83+
! CHECK: %[[VAL_6:.*]]:3 = fir.box_dims %[[VAL_4]], %[[VAL_5]] : (!fir.box<!fir.ptr<!fir.array<?x?xf32>>>, index) -> (index, index, index)
84+
! CHECK: %[[VAL_7:.*]] = fir.convert %[[VAL_6]]#0 : (index) -> i64
85+
! CHECK: hlfir.assign %[[VAL_7]] to %{{.*}}

0 commit comments

Comments
 (0)