@@ -42,6 +42,8 @@ static llvm::cl::opt<bool> useHlfirIntrinsicOps(
42
42
llvm::cl::desc(" Lower via HLFIR transformational intrinsic operations such "
43
43
" as hlfir.sum" ));
44
44
45
+ static constexpr char tempResultName[] = " .tmp.func_result" ;
46
+
45
47
// / Helper to package a Value and its properties into an ExtendedValue.
46
48
static fir::ExtendedValue toExtendedValue (mlir::Location loc, mlir::Value base,
47
49
llvm::ArrayRef<mlir::Value> extents,
@@ -147,7 +149,7 @@ static bool mustCastFuncOpToCopeWithImplicitInterfaceMismatch(
147
149
return false ;
148
150
}
149
151
150
- fir::ExtendedValue Fortran::lower::genCallOpAndResult (
152
+ std::pair< fir::ExtendedValue, bool > Fortran::lower::genCallOpAndResult (
151
153
mlir::Location loc, Fortran::lower::AbstractConverter &converter,
152
154
Fortran::lower::SymMap &symMap, Fortran::lower::StatementContext &stmtCtx,
153
155
Fortran::lower::CallerInterface &caller, mlir::FunctionType callSiteType,
@@ -478,6 +480,7 @@ fir::ExtendedValue Fortran::lower::genCallOpAndResult(
478
480
[](const auto &) {});
479
481
480
482
// 7.5.6.3 point 5. Derived-type finalization for nonpointer function.
483
+ bool resultIsFinalized = false ;
481
484
// Check if the derived-type is finalizable if it is a monomorphic
482
485
// derived-type.
483
486
// For polymorphic and unlimited polymorphic enities call the runtime
@@ -499,6 +502,7 @@ fir::ExtendedValue Fortran::lower::genCallOpAndResult(
499
502
fir::runtime::genDerivedTypeDestroy (*bldr, loc,
500
503
fir::getBase (*allocatedResult));
501
504
});
505
+ resultIsFinalized = true ;
502
506
} else {
503
507
const Fortran::semantics::DerivedTypeSpec &typeSpec =
504
508
retTy->GetDerivedTypeSpec ();
@@ -513,14 +517,17 @@ fir::ExtendedValue Fortran::lower::genCallOpAndResult(
513
517
mlir::Value box = bldr->createBox (loc, *allocatedResult);
514
518
fir::runtime::genDerivedTypeDestroy (*bldr, loc, box);
515
519
});
520
+ resultIsFinalized = true ;
516
521
}
517
522
}
518
523
}
519
- return *allocatedResult;
524
+ return { *allocatedResult, resultIsFinalized} ;
520
525
}
521
526
527
+ // subroutine call
522
528
if (!resultType)
523
- return mlir::Value{}; // subroutine call
529
+ return {fir::ExtendedValue{mlir::Value{}}, /* resultIsFinalized=*/ false };
530
+
524
531
// For now, Fortran return values are implemented with a single MLIR
525
532
// function return value.
526
533
assert (callNumResults == 1 && " Expected exactly one result in FUNCTION call" );
@@ -533,10 +540,10 @@ fir::ExtendedValue Fortran::lower::genCallOpAndResult(
533
540
funcType.getResults ()[0 ].dyn_cast <fir::CharacterType>();
534
541
mlir::Value len = builder.createIntegerConstant (
535
542
loc, builder.getCharacterLengthType (), charTy.getLen ());
536
- return fir::CharBoxValue{callResult, len};
543
+ return { fir::CharBoxValue{callResult, len}, /* resultIsFinalized= */ false };
537
544
}
538
545
539
- return callResult;
546
+ return { callResult, /* resultIsFinalized= */ false } ;
540
547
}
541
548
542
549
static hlfir::EntityWithAttributes genStmtFunctionRef (
@@ -1389,7 +1396,7 @@ genUserCall(Fortran::lower::PreparedActualArguments &loweredActuals,
1389
1396
// Prepare lowered arguments according to the interface
1390
1397
// and map the lowered values to the dummy
1391
1398
// arguments.
1392
- fir::ExtendedValue result = Fortran::lower::genCallOpAndResult (
1399
+ auto [ result, resultIsFinalized] = Fortran::lower::genCallOpAndResult (
1393
1400
loc, callContext.converter , callContext.symMap , callContext.stmtCtx ,
1394
1401
caller, callSiteType, callContext.resultType ,
1395
1402
callContext.isElementalProcWithArrayArgs ());
@@ -1404,24 +1411,43 @@ genUserCall(Fortran::lower::PreparedActualArguments &loweredActuals,
1404
1411
if (!fir::getBase (result))
1405
1412
return std::nullopt; // subroutine call.
1406
1413
1407
- hlfir::Entity resultEntity =
1408
- extendedValueToHlfirEntity (loc, builder, result, " .tmp.func_result " );
1414
+ if ( fir::isPointerType ( fir::getBase (result). getType ()))
1415
+ return extendedValueToHlfirEntity (loc, builder, result, tempResultName );
1409
1416
1410
- if (!fir::isPointerType (fir::getBase (result).getType ())) {
1417
+ if (!resultIsFinalized) {
1418
+ hlfir::Entity resultEntity =
1419
+ extendedValueToHlfirEntity (loc, builder, result, tempResultName);
1411
1420
resultEntity = loadTrivialScalar (loc, builder, resultEntity);
1412
-
1413
1421
if (resultEntity.isVariable ()) {
1414
- // Function result must not be freed, since it is allocated on the stack.
1415
- // Note that in non-elemental case, genCallOpAndResult()
1416
- // is responsible for establishing the clean-up that destroys
1417
- // the derived type result or deallocates its components
1418
- // without finalization.
1422
+ // If the result has no finalization, it can be moved into an expression.
1423
+ // In such case, the expression should not be freed after its use since
1424
+ // the result is stack allocated or deallocation (for allocatable results)
1425
+ // was already inserted in genCallOpAndResult.
1419
1426
auto asExpr = builder.create <hlfir::AsExprOp>(
1420
1427
loc, resultEntity, /* mustFree=*/ builder.createBool (loc, false ));
1421
- resultEntity = hlfir::EntityWithAttributes{asExpr.getResult ()};
1428
+ return hlfir::EntityWithAttributes{asExpr.getResult ()};
1422
1429
}
1430
+ return hlfir::EntityWithAttributes{resultEntity};
1423
1431
}
1424
- return hlfir::EntityWithAttributes{resultEntity};
1432
+ // If the result has finalization, it cannot be moved because use of its
1433
+ // value have been created in the statement context and may be emitted
1434
+ // after the hlfir.expr destroy, so the result is kept as a variable in
1435
+ // HLFIR. This may lead to copies when passing the result to an argument
1436
+ // with VALUE, and this do not convey the fact that the result will not
1437
+ // change, but is correct, and using hlfir.expr without the move would
1438
+ // trigger a copy that may be avoided.
1439
+
1440
+ // Load allocatable results before emitting the hlfir.declare and drop its
1441
+ // lower bounds: this is not a variable From the Fortran point of view, so
1442
+ // the lower bounds are ones when inquired on the caller side.
1443
+ const auto *allocatable = result.getBoxOf <fir::MutableBoxValue>();
1444
+ fir::ExtendedValue loadedResult =
1445
+ allocatable
1446
+ ? fir::factory::genMutableBoxRead (builder, loc, *allocatable,
1447
+ /* mayBePolymorphic=*/ true ,
1448
+ /* preserveLowerBounds=*/ false )
1449
+ : result;
1450
+ return extendedValueToHlfirEntity (loc, builder, loadedResult, tempResultName);
1425
1451
}
1426
1452
1427
1453
// / Create an optional dummy argument value from an entity that may be
0 commit comments