Skip to content

Commit a49f630

Browse files
authored
[flang] Lower passing non assumed-rank/size to assumed-ranks (#79145)
Start implementing assumed-rank support as described in https://github.com/llvm/llvm-project/blob/main/flang/docs/AssumedRank.md This commit holds the minimal support for lowering calls to procedure with assumed-rank arguments where the procedure implementation is done in C. The case for passing assumed-size to assumed-rank is left TODO since it will be done a change in assumed-size lowering that is better done in another patch. Care is taken to set the lower bounds to zero when passing non allocatable no pointer as descriptor to a BIND(C) procedure as required per 18.5.3 point 3. This was not done before while the requirements also applies to non assumed-rank descriptors. This change required special attention with IGNORE_TKR(t) to avoid emitting invalid fir.rebox operations (the actual argument type must be used in this case as the output type). Implementation of Fortran procedure with assumed-rank arguments is still TODO.
1 parent 157b626 commit a49f630

File tree

13 files changed

+526
-77
lines changed

13 files changed

+526
-77
lines changed

flang/include/flang/Optimizer/Builder/FIRBuilder.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,8 @@ class FirOpBuilder : public mlir::OpBuilder, public mlir::OpBuilder::Listener {
109109
/// after type conversion and the imaginary part is zero.
110110
mlir::Value convertWithSemantics(mlir::Location loc, mlir::Type toTy,
111111
mlir::Value val,
112-
bool allowCharacterConversion = false);
112+
bool allowCharacterConversion = false,
113+
bool allowRebox = false);
113114

114115
/// Get the entry block of the current Function
115116
mlir::Block *getEntryBlock() { return &getFunction().front(); }

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,9 @@ class Entity : public mlir::Value {
7171
/// Is this an array or an assumed ranked entity?
7272
bool isArray() const { return getRank() != 0; }
7373

74+
/// Is this an assumed ranked entity?
75+
bool isAssumedRank() const { return getRank() == -1; }
76+
7477
/// Return the rank of this entity or -1 if it is an assumed rank.
7578
int getRank() const {
7679
mlir::Type type = fir::unwrapPassByRefType(fir::unwrapRefType(getType()));

flang/include/flang/Optimizer/Dialect/FIRType.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,13 @@ class BaseBoxType : public mlir::Type {
4646
/// Unwrap element type from fir.heap, fir.ptr and fir.array.
4747
mlir::Type unwrapInnerType() const;
4848

49+
/// Is this the box for an assumed rank?
50+
bool isAssumedRank() const;
51+
52+
/// Return the same type, except for the shape, that is taken the shape
53+
/// of shapeMold.
54+
BaseBoxType getBoxTypeWithNewShape(mlir::Type shapeMold) const;
55+
4956
/// Methods for support type inquiry through isa, cast, and dyn_cast.
5057
static bool classof(mlir::Type type);
5158
};
@@ -428,6 +435,13 @@ inline mlir::Type updateTypeForUnlimitedPolymorphic(mlir::Type ty) {
428435
return ty;
429436
}
430437

438+
/// Replace the element type of \p type by \p newElementType, preserving
439+
/// all other layers of the type (fir.ref/ptr/heap/array/box/class).
440+
/// If \p turnBoxIntoClass and the input is a fir.box, it will be turned into
441+
/// a fir.class in the result.
442+
mlir::Type changeElementType(mlir::Type type, mlir::Type newElementType,
443+
bool turnBoxIntoClass);
444+
431445
/// Is `t` an address to fir.box or class type?
432446
inline bool isBoxAddress(mlir::Type t) {
433447
return fir::isa_ref_type(t) && fir::unwrapRefType(t).isa<fir::BaseBoxType>();

flang/lib/Lower/CallInterface.cpp

Lines changed: 17 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -867,9 +867,8 @@ class Fortran::lower::CallInterfaceImpl {
867867
getRefType(Fortran::evaluate::DynamicType dynamicType,
868868
const Fortran::evaluate::characteristics::DummyDataObject &obj) {
869869
mlir::Type type = translateDynamicType(dynamicType);
870-
fir::SequenceType::Shape bounds = getBounds(obj.type.shape());
871-
if (!bounds.empty())
872-
type = fir::SequenceType::get(bounds, type);
870+
if (std::optional<fir::SequenceType::Shape> bounds = getBounds(obj.type))
871+
type = fir::SequenceType::get(*bounds, type);
873872
return fir::ReferenceType::get(type);
874873
}
875874

@@ -993,8 +992,6 @@ class Fortran::lower::CallInterfaceImpl {
993992
using ShapeAttr = Fortran::evaluate::characteristics::TypeAndShape::Attr;
994993
const Fortran::evaluate::characteristics::TypeAndShape::Attrs &shapeAttrs =
995994
obj.type.attrs();
996-
if (shapeAttrs.test(ShapeAttr::AssumedRank))
997-
TODO(loc, "assumed rank in procedure interface");
998995
if (shapeAttrs.test(ShapeAttr::Coarray))
999996
TODO(loc, "coarray: dummy argument coarray in procedure interface");
1000997

@@ -1003,9 +1000,8 @@ class Fortran::lower::CallInterfaceImpl {
10031000

10041001
Fortran::evaluate::DynamicType dynamicType = obj.type.type();
10051002
mlir::Type type = translateDynamicType(dynamicType);
1006-
fir::SequenceType::Shape bounds = getBounds(obj.type.shape());
1007-
if (!bounds.empty())
1008-
type = fir::SequenceType::get(bounds, type);
1003+
if (std::optional<fir::SequenceType::Shape> bounds = getBounds(obj.type))
1004+
type = fir::SequenceType::get(*bounds, type);
10091005
if (obj.attrs.test(Attrs::Allocatable))
10101006
type = fir::HeapType::get(type);
10111007
if (obj.attrs.test(Attrs::Pointer))
@@ -1123,14 +1119,14 @@ class Fortran::lower::CallInterfaceImpl {
11231119
result.GetTypeAndShape();
11241120
assert(typeAndShape && "expect type for non proc pointer result");
11251121
mlirType = translateDynamicType(typeAndShape->type());
1126-
fir::SequenceType::Shape bounds = getBounds(typeAndShape->shape());
11271122
const auto *resTypeAndShape{result.GetTypeAndShape()};
11281123
bool resIsPolymorphic =
11291124
resTypeAndShape && resTypeAndShape->type().IsPolymorphic();
11301125
bool resIsAssumedType =
11311126
resTypeAndShape && resTypeAndShape->type().IsAssumedType();
1132-
if (!bounds.empty())
1133-
mlirType = fir::SequenceType::get(bounds, mlirType);
1127+
if (std::optional<fir::SequenceType::Shape> bounds =
1128+
getBounds(*typeAndShape))
1129+
mlirType = fir::SequenceType::get(*bounds, mlirType);
11341130
if (result.attrs.test(Attr::Allocatable))
11351131
mlirType = fir::wrapInClassOrBoxType(
11361132
fir::HeapType::get(mlirType), resIsPolymorphic, resIsAssumedType);
@@ -1157,9 +1153,17 @@ class Fortran::lower::CallInterfaceImpl {
11571153
setSaveResult();
11581154
}
11591155

1160-
fir::SequenceType::Shape getBounds(const Fortran::evaluate::Shape &shape) {
1156+
// Return nullopt for scalars, empty vector for assumed rank, and a vector
1157+
// with the shape (may contain unknown extents) for arrays.
1158+
std::optional<fir::SequenceType::Shape> getBounds(
1159+
const Fortran::evaluate::characteristics::TypeAndShape &typeAndShape) {
1160+
using ShapeAttr = Fortran::evaluate::characteristics::TypeAndShape::Attr;
1161+
if (typeAndShape.shape().empty() &&
1162+
!typeAndShape.attrs().test(ShapeAttr::AssumedRank))
1163+
return std::nullopt;
11611164
fir::SequenceType::Shape bounds;
1162-
for (const std::optional<Fortran::evaluate::ExtentExpr> &extent : shape) {
1165+
for (const std::optional<Fortran::evaluate::ExtentExpr> &extent :
1166+
typeAndShape.shape()) {
11631167
fir::SequenceType::Extent bound = fir::SequenceType::getUnknownExtent();
11641168
if (std::optional<std::int64_t> i = toInt64(extent))
11651169
bound = *i;

0 commit comments

Comments
 (0)