Skip to content

Commit cedfd27

Browse files
committed
[flang][hlfir] Lower procedure designators to HLFIR
- Add a convertProcedureDesignatorToHLFIR that converts the fir::ExtendedValue from the current lowering to a fir.boxproc/tuple<fir.boxproc, len> mlir::Value. - Allow fir.boxproc/tuple<fir.boxproc, len> as hlfir::Entity values (a function is an address, but from a Fortran entity point of view, procedure that are not procedure pointers cannot be assigned to, so it makes a lot more sense to consider those as values). - Modify symbol association to not generate an hlfir.declare for dummy procedures. They are not needed and allowing hlfir.declare to declare function values would make its verifier and handling overly complex for little benefits (maybe an hlfir.declare_proc could be added if it turnout out useful later for debug info and attributes storing purposes). - Allow translation from hlfir::Entity to fir::ExtendedValue. convertToBox return type had to be relaxed because some intrinsics handles both object and procedure arguments and need to lower their object arguments "asBox". fir::BoxValue is not intended to carry dummy procedures (all its member functions would make little sense and its verifier does not accept such type). Note that AsAddr, AsValue and AsBox will always return the same MLIR value for procedure designators because they are always handled the same way in FIR. Differential Revision: https://reviews.llvm.org/D143585
1 parent f37d7c9 commit cedfd27

File tree

14 files changed

+297
-33
lines changed

14 files changed

+297
-33
lines changed

flang/include/flang/Lower/CallInterface.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -429,6 +429,9 @@ getOrDeclareFunction(llvm::StringRef name,
429429
mlir::Type getDummyProcedureType(const Fortran::semantics::Symbol &dummyProc,
430430
Fortran::lower::AbstractConverter &);
431431

432+
/// Return !fir.boxproc<() -> ()> type.
433+
mlir::Type getUntypedBoxProcType(mlir::MLIRContext *context);
434+
432435
/// Return true if \p ty is "!fir.ref<i64>", which is the interface for
433436
/// type(C_PTR/C_FUNPTR) passed by value.
434437
bool isCPtrArgByValueType(mlir::Type ty);

flang/include/flang/Lower/ConvertExprToHLFIR.h

Lines changed: 16 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -48,21 +48,24 @@ translateToExtendedValue(mlir::Location loc, fir::FirOpBuilder &builder,
4848
return exv;
4949
}
5050

51-
/// Lower an evaluate::Expr to a fir::Box.
52-
fir::BoxValue convertExprToBox(mlir::Location loc,
53-
Fortran::lower::AbstractConverter &,
54-
const Fortran::lower::SomeExpr &,
55-
Fortran::lower::SymMap &,
56-
Fortran::lower::StatementContext &);
57-
fir::BoxValue convertToBox(mlir::Location loc,
58-
Fortran::lower::AbstractConverter &,
59-
hlfir::Entity entity,
60-
Fortran::lower::StatementContext &,
61-
mlir::Type fortranType);
51+
/// Lower an evaluate::Expr object to a fir.box, and a procedure designator to a
52+
/// fir.boxproc<>
53+
fir::ExtendedValue convertExprToBox(mlir::Location loc,
54+
Fortran::lower::AbstractConverter &,
55+
const Fortran::lower::SomeExpr &,
56+
Fortran::lower::SymMap &,
57+
Fortran::lower::StatementContext &);
58+
fir::ExtendedValue convertToBox(mlir::Location loc,
59+
Fortran::lower::AbstractConverter &,
60+
hlfir::Entity entity,
61+
Fortran::lower::StatementContext &,
62+
mlir::Type fortranType);
6263

6364
/// Lower an evaluate::Expr to fir::ExtendedValue address.
64-
/// The address may be a raw fir.ref<T>, or a fir.box<T>/fir.class<T>, (pointer
65-
/// and allocatable are dereferenced).
65+
/// The address may be a raw fir.ref<T>, or a fir.box<T>/fir.class<T>, or a
66+
/// fir.boxproc<>. Pointers and allocatable are dereferenced.
67+
/// - If the expression is a procedure designator, it is lowered to fir.boxproc
68+
/// (with an extra length for character function procedure designators).
6669
/// - If expression is not a variable, or is a designator with vector
6770
/// subscripts, a temporary is created to hold the expression value and
6871
/// is returned as:

flang/include/flang/Lower/ConvertProcedureDesignator.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,9 @@ class Location;
2323
namespace fir {
2424
class ExtendedValue;
2525
}
26+
namespace hlfir {
27+
class EntityWithAttributes;
28+
}
2629
namespace Fortran::evaluate {
2730
struct ProcedureDesignator;
2831
}
@@ -40,5 +43,12 @@ fir::ExtendedValue convertProcedureDesignator(
4043
const Fortran::evaluate::ProcedureDesignator &proc,
4144
Fortran::lower::SymMap &symMap, Fortran::lower::StatementContext &stmtCtx);
4245

46+
/// Lower a procedure designator to a !fir.boxproc<()->() or
47+
/// tuple<!fir.boxproc<()->(), len>.
48+
hlfir::EntityWithAttributes convertProcedureDesignatorToHLFIR(
49+
mlir::Location loc, Fortran::lower::AbstractConverter &converter,
50+
const Fortran::evaluate::ProcedureDesignator &proc,
51+
Fortran::lower::SymMap &symMap, Fortran::lower::StatementContext &stmtCtx);
52+
4353
} // namespace Fortran::lower
4454
#endif // FORTRAN_LOWER_CONVERT_PROCEDURE_DESIGNATOR_H

flang/include/flang/Optimizer/Builder/Character.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -224,9 +224,11 @@ mlir::Value createCharacterProcedureTuple(fir::FirOpBuilder &builder,
224224

225225
/// Given a tuple containing a character function address and its result length,
226226
/// extract the tuple into a pair of value <function address, result length>.
227+
/// If openBoxProc is true, the function address is extracted from the
228+
/// fir.boxproc, otherwise, the returned function address is the fir.boxproc.
227229
std::pair<mlir::Value, mlir::Value>
228230
extractCharacterProcedureTuple(fir::FirOpBuilder &builder, mlir::Location loc,
229-
mlir::Value tuple);
231+
mlir::Value tuple, bool openBoxProc = true);
230232

231233
} // namespace fir::factory
232234

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

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,18 @@ class AssociateOp;
2929
class ElementalOp;
3030
class YieldElementOp;
3131

32+
/// Is this an SSA value type for the value of a Fortran procedure
33+
/// designator ?
34+
inline bool isFortranProcedureValue(mlir::Type type) {
35+
return type.isa<fir::BoxProcType>() ||
36+
(type.isa<mlir::TupleType>() &&
37+
fir::isCharacterProcedureTuple(type, /*acceptRawFunc=*/false));
38+
}
39+
3240
/// Is this an SSA value type for the value of a Fortran expression?
3341
inline bool isFortranValueType(mlir::Type type) {
34-
return type.isa<hlfir::ExprType>() || fir::isa_trivial(type);
42+
return type.isa<hlfir::ExprType>() || fir::isa_trivial(type) ||
43+
isFortranProcedureValue(type);
3544
}
3645

3746
/// Is this the value of a Fortran expression in an SSA value form?
@@ -77,6 +86,10 @@ class Entity : public mlir::Value {
7786
bool isBoxAddressOrValue() const {
7887
return hlfir::isBoxAddressOrValueType(getType());
7988
}
89+
90+
/// Is this entity a procedure designator?
91+
bool isProcedure() const { return isFortranProcedureValue(getType()); }
92+
8093
/// Is this an array or an assumed ranked entity?
8194
bool isArray() const { return getRank() != 0; }
8295

@@ -357,7 +370,7 @@ std::pair<fir::ExtendedValue, std::optional<hlfir::CleanupFunction>>
357370
convertToAddress(mlir::Location loc, fir::FirOpBuilder &builder,
358371
const hlfir::Entity &entity, mlir::Type targetType);
359372

360-
std::pair<fir::BoxValue, std::optional<hlfir::CleanupFunction>>
373+
std::pair<fir::ExtendedValue, std::optional<hlfir::CleanupFunction>>
361374
convertToBox(mlir::Location loc, fir::FirOpBuilder &builder,
362375
const hlfir::Entity &entity, mlir::Type targetType);
363376
} // namespace hlfir

flang/lib/Lower/Bridge.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -807,6 +807,12 @@ class FirConverter : public Fortran::lower::AbstractConverter {
807807
},
808808
[](auto x) -> Fortran::lower::SymbolBox { return x; });
809809
}
810+
// Procedure dummies are not mapped with an hlfir.declare because
811+
// they are not "variable" (cannot be assigned to), and it would
812+
// make hlfir.declare more complex than it needs to to allow this.
813+
// Do a regular lookup.
814+
if (Fortran::semantics::IsProcedure(sym))
815+
return symMap->lookupSymbol(sym);
810816
return {};
811817
}
812818
if (Fortran::lower::SymbolBox v = symMap->lookupSymbol(sym))

flang/lib/Lower/CallInterface.cpp

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -39,24 +39,27 @@ static std::string getMangledName(mlir::Location loc,
3939
return bindName ? *bindName : Fortran::lower::mangle::mangleName(symbol);
4040
}
4141

42+
mlir::Type Fortran::lower::getUntypedBoxProcType(mlir::MLIRContext *context) {
43+
llvm::SmallVector<mlir::Type> resultTys;
44+
llvm::SmallVector<mlir::Type> inputTys;
45+
auto untypedFunc = mlir::FunctionType::get(context, inputTys, resultTys);
46+
return fir::BoxProcType::get(context, untypedFunc);
47+
}
48+
4249
/// Return the type of a dummy procedure given its characteristic (if it has
4350
/// one).
44-
mlir::Type getProcedureDesignatorType(
51+
static mlir::Type getProcedureDesignatorType(
4552
const Fortran::evaluate::characteristics::Procedure *,
4653
Fortran::lower::AbstractConverter &converter) {
4754
// TODO: Get actual function type of the dummy procedure, at least when an
4855
// interface is given. The result type should be available even if the arity
4956
// and type of the arguments is not.
50-
llvm::SmallVector<mlir::Type> resultTys;
51-
llvm::SmallVector<mlir::Type> inputTys;
5257
// In general, that is a nice to have but we cannot guarantee to find the
5358
// function type that will match the one of the calls, we may not even know
5459
// how many arguments the dummy procedure accepts (e.g. if a procedure
5560
// pointer is only transiting through the current procedure without being
5661
// called), so a function type cast must always be inserted.
57-
auto *context = &converter.getMLIRContext();
58-
auto untypedFunc = mlir::FunctionType::get(context, inputTys, resultTys);
59-
return fir::BoxProcType::get(context, untypedFunc);
62+
return Fortran::lower::getUntypedBoxProcType(&converter.getMLIRContext());
6063
}
6164

6265
//===----------------------------------------------------------------------===//

flang/lib/Lower/ConvertCall.cpp

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -782,6 +782,11 @@ static PreparedDummyArgument preparePresentUserCallActualArgument(
782782
// element if this is an array in an elemental call.
783783
hlfir::Entity actual = preparedActual.getActual(loc, builder);
784784

785+
// Do nothing if this is a procedure argument. It is already a
786+
// fir.boxproc/fir.tuple<fir.boxproc, len> as it should.
787+
if (actual.isProcedure())
788+
return PreparedDummyArgument{actual, std::nullopt};
789+
785790
const bool passingPolymorphicToNonPolymorphic =
786791
actual.isPolymorphic() && !fir::isPolymorphicType(dummyType);
787792

@@ -1013,7 +1018,10 @@ genUserCall(PreparedActualArguments &loweredActuals,
10131018
loc, "unexpected PassBy::AddressAndLength for actual arguments");
10141019
break;
10151020
case PassBy::CharProcTuple: {
1016-
TODO(loc, "HLFIR PassBy::CharProcTuple");
1021+
hlfir::Entity actual = preparedActual->getActual(loc, builder);
1022+
assert(fir::isCharacterProcedureTuple(actual.getType()) &&
1023+
"character dummy procedure was not prepared as expected");
1024+
caller.placeInput(arg, actual);
10171025
} break;
10181026
case PassBy::MutableBox: {
10191027
hlfir::Entity actual = preparedActual->getActual(loc, builder);

flang/lib/Lower/ConvertExprToHLFIR.cpp

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#include "flang/Lower/CallInterface.h"
1717
#include "flang/Lower/ConvertCall.h"
1818
#include "flang/Lower/ConvertConstant.h"
19+
#include "flang/Lower/ConvertProcedureDesignator.h"
1920
#include "flang/Lower/ConvertType.h"
2021
#include "flang/Lower/ConvertVariable.h"
2122
#include "flang/Lower/StatementContext.h"
@@ -1024,9 +1025,11 @@ class HlfirBuilder {
10241025
}
10251026

10261027
hlfir::EntityWithAttributes
1027-
gen(const Fortran::evaluate::ProcedureDesignator &expr) {
1028-
TODO(getLoc(), "lowering ProcDes to HLFIR");
1028+
gen(const Fortran::evaluate::ProcedureDesignator &proc) {
1029+
return Fortran::lower::convertProcedureDesignatorToHLFIR(
1030+
getLoc(), getConverter(), proc, getSymMap(), getStmtCtx());
10291031
}
1032+
10301033
hlfir::EntityWithAttributes gen(const Fortran::evaluate::ProcedureRef &expr) {
10311034
TODO(getLoc(), "lowering ProcRef to HLFIR");
10321035
}
@@ -1256,7 +1259,7 @@ hlfir::EntityWithAttributes Fortran::lower::convertExprToHLFIR(
12561259
return HlfirBuilder(loc, converter, symMap, stmtCtx).gen(expr);
12571260
}
12581261

1259-
fir::BoxValue Fortran::lower::convertToBox(
1262+
fir::ExtendedValue Fortran::lower::convertToBox(
12601263
mlir::Location loc, Fortran::lower::AbstractConverter &converter,
12611264
hlfir::Entity entity, Fortran::lower::StatementContext &stmtCtx,
12621265
mlir::Type fortranType) {
@@ -1266,7 +1269,8 @@ fir::BoxValue Fortran::lower::convertToBox(
12661269
stmtCtx.attachCleanup(*cleanup);
12671270
return exv;
12681271
}
1269-
fir::BoxValue Fortran::lower::convertExprToBox(
1272+
1273+
fir::ExtendedValue Fortran::lower::convertExprToBox(
12701274
mlir::Location loc, Fortran::lower::AbstractConverter &converter,
12711275
const Fortran::lower::SomeExpr &expr, Fortran::lower::SymMap &symMap,
12721276
Fortran::lower::StatementContext &stmtCtx) {

flang/lib/Lower/ConvertProcedureDesignator.cpp

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,3 +93,35 @@ fir::ExtendedValue Fortran::lower::convertProcedureDesignator(
9393
}
9494
return funcPtr;
9595
}
96+
97+
hlfir::EntityWithAttributes Fortran::lower::convertProcedureDesignatorToHLFIR(
98+
mlir::Location loc, Fortran::lower::AbstractConverter &converter,
99+
const Fortran::evaluate::ProcedureDesignator &proc,
100+
Fortran::lower::SymMap &symMap, Fortran::lower::StatementContext &stmtCtx) {
101+
fir::ExtendedValue procExv =
102+
convertProcedureDesignator(loc, converter, proc, symMap, stmtCtx);
103+
// Directly package the procedure address as a fir.boxproc or
104+
// tuple<fir.boxbroc, len> so that it can be returned as a single mlir::Value.
105+
fir::FirOpBuilder &builder = converter.getFirOpBuilder();
106+
107+
mlir::Value funcAddr = fir::getBase(procExv);
108+
if (!funcAddr.getType().isa<fir::BoxProcType>()) {
109+
mlir::Type boxTy =
110+
Fortran::lower::getUntypedBoxProcType(&converter.getMLIRContext());
111+
if (auto host = Fortran::lower::argumentHostAssocs(converter, funcAddr))
112+
funcAddr = builder.create<fir::EmboxProcOp>(
113+
loc, boxTy, llvm::ArrayRef<mlir::Value>{funcAddr, host});
114+
else
115+
funcAddr = builder.create<fir::EmboxProcOp>(loc, boxTy, funcAddr);
116+
}
117+
118+
mlir::Value res = procExv.match(
119+
[&](const fir::CharBoxValue &box) -> mlir::Value {
120+
mlir::Type tupleTy =
121+
fir::factory::getCharacterProcedureTupleType(funcAddr.getType());
122+
return fir::factory::createCharacterProcedureTuple(
123+
builder, loc, tupleTy, funcAddr, box.getLen());
124+
},
125+
[funcAddr](const auto &) { return funcAddr; });
126+
return hlfir::EntityWithAttributes{res};
127+
}

flang/lib/Lower/ConvertVariable.cpp

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1439,7 +1439,13 @@ static void genDeclareSymbol(Fortran::lower::AbstractConverter &converter,
14391439
llvm::ArrayRef<mlir::Value> shape = std::nullopt,
14401440
llvm::ArrayRef<mlir::Value> lbounds = std::nullopt,
14411441
bool force = false) {
1442-
if (converter.getLoweringOptions().getLowerToHighLevelFIR()) {
1442+
// In HLFIR, procedure dummy symbols are not added with an hlfir.declare
1443+
// because they are "values", and hlfir.declare is intended for variables. It
1444+
// would add too much complexity to hlfir.declare to support this case, and
1445+
// this would bring very little (the only point being debug info, that are not
1446+
// yet emitted) since alias analysis is meaningless for those.
1447+
if (converter.getLoweringOptions().getLowerToHighLevelFIR() &&
1448+
!Fortran::semantics::IsProcedure(sym)) {
14431449
fir::FirOpBuilder &builder = converter.getFirOpBuilder();
14441450
const mlir::Location loc = genLocation(converter, sym);
14451451
mlir::Value shapeOrShift;
@@ -1488,7 +1494,8 @@ void Fortran::lower::genDeclareSymbol(
14881494
Fortran::lower::AbstractConverter &converter,
14891495
Fortran::lower::SymMap &symMap, const Fortran::semantics::Symbol &sym,
14901496
const fir::ExtendedValue &exv, bool force) {
1491-
if (converter.getLoweringOptions().getLowerToHighLevelFIR()) {
1497+
if (converter.getLoweringOptions().getLowerToHighLevelFIR() &&
1498+
!Fortran::semantics::IsProcedure(sym)) {
14921499
fir::FirOpBuilder &builder = converter.getFirOpBuilder();
14931500
const mlir::Location loc = genLocation(converter, sym);
14941501
fir::FortranVariableFlagsAttr attributes =

flang/lib/Optimizer/Builder/Character.cpp

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -710,15 +710,17 @@ mlir::Value fir::factory::CharacterExprHelper::getLength(mlir::Value memref) {
710710
std::pair<mlir::Value, mlir::Value>
711711
fir::factory::extractCharacterProcedureTuple(fir::FirOpBuilder &builder,
712712
mlir::Location loc,
713-
mlir::Value tuple) {
713+
mlir::Value tuple,
714+
bool openBoxProc) {
714715
mlir::TupleType tupleType = tuple.getType().cast<mlir::TupleType>();
715716
mlir::Value addr = builder.create<fir::ExtractValueOp>(
716717
loc, tupleType.getType(0), tuple,
717718
builder.getArrayAttr(
718719
{builder.getIntegerAttr(builder.getIndexType(), 0)}));
719720
mlir::Value proc = [&]() -> mlir::Value {
720-
if (auto addrTy = addr.getType().dyn_cast<fir::BoxProcType>())
721-
return builder.create<fir::BoxAddrOp>(loc, addrTy.getEleTy(), addr);
721+
if (openBoxProc)
722+
if (auto addrTy = addr.getType().dyn_cast<fir::BoxProcType>())
723+
return builder.create<fir::BoxAddrOp>(loc, addrTy.getEleTy(), addr);
722724
return addr;
723725
}();
724726
mlir::Value len = builder.create<fir::ExtractValueOp>(

flang/lib/Optimizer/Builder/HLFIRTools.cpp

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -806,6 +806,15 @@ hlfir::translateToExtendedValue(mlir::Location loc, fir::FirOpBuilder &builder,
806806
return {translateVariableToExtendedValue(loc, builder, entity),
807807
std::nullopt};
808808

809+
if (entity.isProcedure()) {
810+
if (fir::isCharacterProcedureTuple(entity.getType())) {
811+
auto [boxProc, len] = fir::factory::extractCharacterProcedureTuple(
812+
builder, loc, entity, /*openBoxProc=*/false);
813+
return {fir::CharBoxValue{boxProc, len}, std::nullopt};
814+
}
815+
return {static_cast<mlir::Value>(entity), std::nullopt};
816+
}
817+
809818
if (entity.getType().isa<hlfir::ExprType>()) {
810819
hlfir::AssociateOp associate = hlfir::genAssociateExpr(
811820
loc, builder, entity, entity.getType(), "adapt.valuebyref");
@@ -856,10 +865,14 @@ static fir::ExtendedValue placeTrivialInMemory(mlir::Location loc,
856865
return temp;
857866
}
858867

859-
std::pair<fir::BoxValue, std::optional<hlfir::CleanupFunction>>
868+
std::pair<fir::ExtendedValue, std::optional<hlfir::CleanupFunction>>
860869
hlfir::convertToBox(mlir::Location loc, fir::FirOpBuilder &builder,
861870
const hlfir::Entity &entity, mlir::Type targetType) {
862871
auto [exv, cleanup] = translateToExtendedValue(loc, builder, entity);
872+
// Procedure entities should not go through createBoxValue that embox
873+
// object entities. Return the fir.boxproc directly.
874+
if (entity.isProcedure())
875+
return {exv, cleanup};
863876
mlir::Value base = fir::getBase(exv);
864877
if (fir::isa_trivial(base.getType()))
865878
exv = placeTrivialInMemory(loc, builder, base, targetType);

0 commit comments

Comments
 (0)