Skip to content

Commit

Permalink
[flang] Lower passing non assumed-rank/size to assumed-ranks (#79145)
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
jeanPerier committed Jan 26, 2024
1 parent 157b626 commit a49f630
Show file tree
Hide file tree
Showing 13 changed files with 526 additions and 77 deletions.
3 changes: 2 additions & 1 deletion flang/include/flang/Optimizer/Builder/FIRBuilder.h
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,8 @@ class FirOpBuilder : public mlir::OpBuilder, public mlir::OpBuilder::Listener {
/// after type conversion and the imaginary part is zero.
mlir::Value convertWithSemantics(mlir::Location loc, mlir::Type toTy,
mlir::Value val,
bool allowCharacterConversion = false);
bool allowCharacterConversion = false,
bool allowRebox = false);

/// Get the entry block of the current Function
mlir::Block *getEntryBlock() { return &getFunction().front(); }
Expand Down
3 changes: 3 additions & 0 deletions flang/include/flang/Optimizer/Builder/HLFIRTools.h
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,9 @@ class Entity : public mlir::Value {
/// Is this an array or an assumed ranked entity?
bool isArray() const { return getRank() != 0; }

/// Is this an assumed ranked entity?
bool isAssumedRank() const { return getRank() == -1; }

/// Return the rank of this entity or -1 if it is an assumed rank.
int getRank() const {
mlir::Type type = fir::unwrapPassByRefType(fir::unwrapRefType(getType()));
Expand Down
14 changes: 14 additions & 0 deletions flang/include/flang/Optimizer/Dialect/FIRType.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,13 @@ class BaseBoxType : public mlir::Type {
/// Unwrap element type from fir.heap, fir.ptr and fir.array.
mlir::Type unwrapInnerType() const;

/// Is this the box for an assumed rank?
bool isAssumedRank() const;

/// Return the same type, except for the shape, that is taken the shape
/// of shapeMold.
BaseBoxType getBoxTypeWithNewShape(mlir::Type shapeMold) const;

/// Methods for support type inquiry through isa, cast, and dyn_cast.
static bool classof(mlir::Type type);
};
Expand Down Expand Up @@ -428,6 +435,13 @@ inline mlir::Type updateTypeForUnlimitedPolymorphic(mlir::Type ty) {
return ty;
}

/// Replace the element type of \p type by \p newElementType, preserving
/// all other layers of the type (fir.ref/ptr/heap/array/box/class).
/// If \p turnBoxIntoClass and the input is a fir.box, it will be turned into
/// a fir.class in the result.
mlir::Type changeElementType(mlir::Type type, mlir::Type newElementType,
bool turnBoxIntoClass);

/// Is `t` an address to fir.box or class type?
inline bool isBoxAddress(mlir::Type t) {
return fir::isa_ref_type(t) && fir::unwrapRefType(t).isa<fir::BaseBoxType>();
Expand Down
30 changes: 17 additions & 13 deletions flang/lib/Lower/CallInterface.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -867,9 +867,8 @@ class Fortran::lower::CallInterfaceImpl {
getRefType(Fortran::evaluate::DynamicType dynamicType,
const Fortran::evaluate::characteristics::DummyDataObject &obj) {
mlir::Type type = translateDynamicType(dynamicType);
fir::SequenceType::Shape bounds = getBounds(obj.type.shape());
if (!bounds.empty())
type = fir::SequenceType::get(bounds, type);
if (std::optional<fir::SequenceType::Shape> bounds = getBounds(obj.type))
type = fir::SequenceType::get(*bounds, type);
return fir::ReferenceType::get(type);
}

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

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

Fortran::evaluate::DynamicType dynamicType = obj.type.type();
mlir::Type type = translateDynamicType(dynamicType);
fir::SequenceType::Shape bounds = getBounds(obj.type.shape());
if (!bounds.empty())
type = fir::SequenceType::get(bounds, type);
if (std::optional<fir::SequenceType::Shape> bounds = getBounds(obj.type))
type = fir::SequenceType::get(*bounds, type);
if (obj.attrs.test(Attrs::Allocatable))
type = fir::HeapType::get(type);
if (obj.attrs.test(Attrs::Pointer))
Expand Down Expand Up @@ -1123,14 +1119,14 @@ class Fortran::lower::CallInterfaceImpl {
result.GetTypeAndShape();
assert(typeAndShape && "expect type for non proc pointer result");
mlirType = translateDynamicType(typeAndShape->type());
fir::SequenceType::Shape bounds = getBounds(typeAndShape->shape());
const auto *resTypeAndShape{result.GetTypeAndShape()};
bool resIsPolymorphic =
resTypeAndShape && resTypeAndShape->type().IsPolymorphic();
bool resIsAssumedType =
resTypeAndShape && resTypeAndShape->type().IsAssumedType();
if (!bounds.empty())
mlirType = fir::SequenceType::get(bounds, mlirType);
if (std::optional<fir::SequenceType::Shape> bounds =
getBounds(*typeAndShape))
mlirType = fir::SequenceType::get(*bounds, mlirType);
if (result.attrs.test(Attr::Allocatable))
mlirType = fir::wrapInClassOrBoxType(
fir::HeapType::get(mlirType), resIsPolymorphic, resIsAssumedType);
Expand All @@ -1157,9 +1153,17 @@ class Fortran::lower::CallInterfaceImpl {
setSaveResult();
}

fir::SequenceType::Shape getBounds(const Fortran::evaluate::Shape &shape) {
// Return nullopt for scalars, empty vector for assumed rank, and a vector
// with the shape (may contain unknown extents) for arrays.
std::optional<fir::SequenceType::Shape> getBounds(
const Fortran::evaluate::characteristics::TypeAndShape &typeAndShape) {
using ShapeAttr = Fortran::evaluate::characteristics::TypeAndShape::Attr;
if (typeAndShape.shape().empty() &&
!typeAndShape.attrs().test(ShapeAttr::AssumedRank))
return std::nullopt;
fir::SequenceType::Shape bounds;
for (const std::optional<Fortran::evaluate::ExtentExpr> &extent : shape) {
for (const std::optional<Fortran::evaluate::ExtentExpr> &extent :
typeAndShape.shape()) {
fir::SequenceType::Extent bound = fir::SequenceType::getUnknownExtent();
if (std::optional<std::int64_t> i = toInt64(extent))
bound = *i;
Expand Down

0 comments on commit a49f630

Please sign in to comment.