Skip to content

Commit 2984699

Browse files
authored
[flang] Implement passing of assumed-type actual arguments. (#83851)
Passing `TYPE(*)`actual to `TYPE(*)` dummy was left TODO. Implement it. The difference with other actual arguments is that `TYPE(*)` are not represented as Fortran::evaluate::Expr<T>, so inquiries on evaluate::Expr<T> must be updated to use evaluate::ActualArgument or also handle semantics::Symbol case (except in portion of the code where `TYPE(*)` is impossible, where asserts are added).
1 parent 74dfded commit 2984699

File tree

2 files changed

+284
-17
lines changed

2 files changed

+284
-17
lines changed

flang/lib/Lower/ConvertCall.cpp

Lines changed: 58 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -970,6 +970,18 @@ mlir::Value static getZeroLowerBounds(mlir::Location loc,
970970
return builder.genShift(loc, lowerBounds);
971971
}
972972

973+
static bool
974+
isSimplyContiguous(const Fortran::evaluate::ActualArgument &arg,
975+
Fortran::evaluate::FoldingContext &foldingContext) {
976+
if (const auto *expr = arg.UnwrapExpr())
977+
return Fortran::evaluate::IsSimplyContiguous(*expr, foldingContext);
978+
const Fortran::semantics::Symbol *sym = arg.GetAssumedTypeDummy();
979+
assert(sym &&
980+
"expect ActualArguments to be expression or assumed-type symbols");
981+
return sym->Rank() == 0 ||
982+
Fortran::evaluate::IsSimplyContiguous(*sym, foldingContext);
983+
}
984+
973985
/// When dummy is not ALLOCATABLE, POINTER and is not passed in register,
974986
/// prepare the actual argument according to the interface. Do as needed:
975987
/// - address element if this is an array argument in an elemental call.
@@ -985,7 +997,7 @@ static PreparedDummyArgument preparePresentUserCallActualArgument(
985997
const Fortran::lower::PreparedActualArgument &preparedActual,
986998
mlir::Type dummyType,
987999
const Fortran::lower::CallerInterface::PassedEntity &arg,
988-
const Fortran::lower::SomeExpr &expr, CallContext &callContext) {
1000+
CallContext &callContext) {
9891001

9901002
Fortran::evaluate::FoldingContext &foldingContext =
9911003
callContext.converter.getFoldingContext();
@@ -1036,7 +1048,7 @@ static PreparedDummyArgument preparePresentUserCallActualArgument(
10361048
const bool mustDoCopyInOut =
10371049
actual.isArray() && arg.mustBeMadeContiguous() &&
10381050
(passingPolymorphicToNonPolymorphic ||
1039-
!Fortran::evaluate::IsSimplyContiguous(expr, foldingContext));
1051+
!isSimplyContiguous(*arg.entity, foldingContext));
10401052

10411053
const bool actualIsAssumedRank = actual.isAssumedRank();
10421054
// Create dummy type with actual argument rank when the dummy is an assumed
@@ -1114,9 +1126,11 @@ static PreparedDummyArgument preparePresentUserCallActualArgument(
11141126
arg.mayBeModifiedByCall() ? copyIn.getVar() : mlir::Value{});
11151127
}
11161128
} else {
1129+
const Fortran::lower::SomeExpr *expr = arg.entity->UnwrapExpr();
1130+
assert(expr && "expression actual argument cannot be an assumed type");
11171131
// The actual is an expression value, place it into a temporary
11181132
// and register the temporary destruction after the call.
1119-
mlir::Type storageType = callContext.converter.genType(expr);
1133+
mlir::Type storageType = callContext.converter.genType(*expr);
11201134
mlir::NamedAttribute byRefAttr = fir::getAdaptToByRefAttr(builder);
11211135
hlfir::AssociateOp associate = hlfir::genAssociateExpr(
11221136
loc, builder, entity, storageType, "", byRefAttr);
@@ -1202,7 +1216,7 @@ static PreparedDummyArgument preparePresentUserCallActualArgument(
12021216
if (auto baseBoxDummy = mlir::dyn_cast<fir::BaseBoxType>(dummyType))
12031217
if (baseBoxDummy.isAssumedRank())
12041218
if (const Fortran::semantics::Symbol *sym =
1205-
Fortran::evaluate::UnwrapWholeSymbolDataRef(expr))
1219+
Fortran::evaluate::UnwrapWholeSymbolDataRef(*arg.entity))
12061220
if (Fortran::semantics::IsAssumedSizeArray(sym->GetUltimate()))
12071221
TODO(loc, "passing assumed-size to assumed-rank array");
12081222

@@ -1224,10 +1238,10 @@ static PreparedDummyArgument prepareUserCallActualArgument(
12241238
const Fortran::lower::PreparedActualArgument &preparedActual,
12251239
mlir::Type dummyType,
12261240
const Fortran::lower::CallerInterface::PassedEntity &arg,
1227-
const Fortran::lower::SomeExpr &expr, CallContext &callContext) {
1241+
CallContext &callContext) {
12281242
if (!preparedActual.handleDynamicOptional())
1229-
return preparePresentUserCallActualArgument(
1230-
loc, builder, preparedActual, dummyType, arg, expr, callContext);
1243+
return preparePresentUserCallActualArgument(loc, builder, preparedActual,
1244+
dummyType, arg, callContext);
12311245

12321246
// Conditional dummy argument preparation. The actual may be absent
12331247
// at runtime, causing any addressing, copy, and packaging to have
@@ -1249,7 +1263,7 @@ static PreparedDummyArgument prepareUserCallActualArgument(
12491263
builder.setInsertionPointToStart(preparationBlock);
12501264
PreparedDummyArgument unconditionalDummy =
12511265
preparePresentUserCallActualArgument(loc, builder, preparedActual,
1252-
dummyType, arg, expr, callContext);
1266+
dummyType, arg, callContext);
12531267
builder.restoreInsertionPoint(insertPt);
12541268

12551269
// TODO: when forwarding an optional to an optional of the same kind
@@ -1291,10 +1305,11 @@ static PreparedDummyArgument prepareProcedurePointerActualArgument(
12911305
const Fortran::lower::PreparedActualArgument &preparedActual,
12921306
mlir::Type dummyType,
12931307
const Fortran::lower::CallerInterface::PassedEntity &arg,
1294-
const Fortran::lower::SomeExpr &expr, CallContext &callContext) {
1308+
CallContext &callContext) {
12951309

12961310
// NULL() actual to procedure pointer dummy
1297-
if (Fortran::evaluate::UnwrapExpr<Fortran::evaluate::NullPointer>(expr) &&
1311+
if (Fortran::evaluate::UnwrapExpr<Fortran::evaluate::NullPointer>(
1312+
*arg.entity) &&
12981313
fir::isBoxProcAddressType(dummyType)) {
12991314
auto boxTy{Fortran::lower::getUntypedBoxProcType(builder.getContext())};
13001315
auto tempBoxProc{builder.createTemporary(loc, boxTy)};
@@ -1335,9 +1350,6 @@ genUserCall(Fortran::lower::PreparedActualArguments &loweredActuals,
13351350
caller.placeInput(arg, builder.genAbsentOp(loc, argTy));
13361351
continue;
13371352
}
1338-
const auto *expr = arg.entity->UnwrapExpr();
1339-
if (!expr)
1340-
TODO(loc, "assumed type actual argument");
13411353

13421354
switch (arg.passBy) {
13431355
case PassBy::Value: {
@@ -1380,15 +1392,15 @@ genUserCall(Fortran::lower::PreparedActualArguments &loweredActuals,
13801392
case PassBy::BaseAddress:
13811393
case PassBy::BoxChar: {
13821394
PreparedDummyArgument preparedDummy = prepareUserCallActualArgument(
1383-
loc, builder, *preparedActual, argTy, arg, *expr, callContext);
1395+
loc, builder, *preparedActual, argTy, arg, callContext);
13841396
callCleanUps.append(preparedDummy.cleanups.rbegin(),
13851397
preparedDummy.cleanups.rend());
13861398
caller.placeInput(arg, preparedDummy.dummy);
13871399
} break;
13881400
case PassBy::BoxProcRef: {
13891401
PreparedDummyArgument preparedDummy =
13901402
prepareProcedurePointerActualArgument(loc, builder, *preparedActual,
1391-
argTy, arg, *expr, callContext);
1403+
argTy, arg, callContext);
13921404
callCleanUps.append(preparedDummy.cleanups.rbegin(),
13931405
preparedDummy.cleanups.rend());
13941406
caller.placeInput(arg, preparedDummy.dummy);
@@ -1408,6 +1420,9 @@ genUserCall(Fortran::lower::PreparedActualArguments &loweredActuals,
14081420
caller.placeInput(arg, actual);
14091421
} break;
14101422
case PassBy::MutableBox: {
1423+
const Fortran::lower::SomeExpr *expr = arg.entity->UnwrapExpr();
1424+
// C709 and C710.
1425+
assert(expr && "cannot pass TYPE(*) to POINTER or ALLOCATABLE");
14111426
hlfir::Entity actual = preparedActual->getActual(loc, builder);
14121427
if (Fortran::evaluate::UnwrapExpr<Fortran::evaluate::NullPointer>(
14131428
*expr)) {
@@ -2405,8 +2420,34 @@ genProcedureRef(CallContext &callContext) {
24052420
caller.getPassedArguments())
24062421
if (const auto *actual = arg.entity) {
24072422
const auto *expr = actual->UnwrapExpr();
2408-
if (!expr)
2409-
TODO(loc, "assumed type actual argument");
2423+
if (!expr) {
2424+
// TYPE(*) actual argument.
2425+
const Fortran::evaluate::Symbol *assumedTypeSym =
2426+
actual->GetAssumedTypeDummy();
2427+
if (!assumedTypeSym)
2428+
fir::emitFatalError(
2429+
loc, "expected assumed-type symbol as actual argument");
2430+
std::optional<fir::FortranVariableOpInterface> var =
2431+
callContext.symMap.lookupVariableDefinition(*assumedTypeSym);
2432+
if (!var)
2433+
fir::emitFatalError(loc, "assumed-type symbol was not lowered");
2434+
hlfir::Entity actual{*var};
2435+
std::optional<mlir::Value> isPresent;
2436+
if (arg.isOptional()) {
2437+
// Passing an optional TYPE(*) to an optional TYPE(*). Note that
2438+
// TYPE(*) cannot be ALLOCATABLE/POINTER (C709) so there is no
2439+
// need to cover the case of passing an ALLOCATABLE/POINTER to an
2440+
// OPTIONAL.
2441+
fir::FirOpBuilder &builder = callContext.getBuilder();
2442+
isPresent =
2443+
builder.create<fir::IsPresentOp>(loc, builder.getI1Type(), actual)
2444+
.getResult();
2445+
}
2446+
loweredActuals.push_back(Fortran::lower::PreparedActualArgument{
2447+
hlfir::Entity{*var}, isPresent});
2448+
continue;
2449+
}
2450+
24102451
if (Fortran::evaluate::UnwrapExpr<Fortran::evaluate::NullPointer>(
24112452
*expr)) {
24122453
if ((arg.passBy !=

0 commit comments

Comments
 (0)