@@ -284,7 +284,8 @@ static void remapActualToDummyDescriptors(
284
284
}
285
285
}
286
286
287
- std::pair<fir::ExtendedValue, bool > Fortran::lower::genCallOpAndResult (
287
+ std::pair<Fortran::lower::LoweredResult, bool >
288
+ Fortran::lower::genCallOpAndResult (
288
289
mlir::Location loc, Fortran::lower::AbstractConverter &converter,
289
290
Fortran::lower::SymMap &symMap, Fortran::lower::StatementContext &stmtCtx,
290
291
Fortran::lower::CallerInterface &caller, mlir::FunctionType callSiteType,
@@ -326,13 +327,20 @@ std::pair<fir::ExtendedValue, bool> Fortran::lower::genCallOpAndResult(
326
327
}
327
328
}
328
329
330
+ const bool isExprCall =
331
+ converter.getLoweringOptions ().getLowerToHighLevelFIR () &&
332
+ callSiteType.getNumResults () == 1 &&
333
+ llvm::isa<fir::SequenceType>(callSiteType.getResult (0 ));
334
+
329
335
mlir::IndexType idxTy = builder.getIndexType ();
330
336
auto lowerSpecExpr = [&](const auto &expr) -> mlir::Value {
331
337
mlir::Value convertExpr = builder.createConvert (
332
338
loc, idxTy, fir::getBase (converter.genExprValue (expr, stmtCtx)));
333
339
return fir::factory::genMaxWithZero (builder, loc, convertExpr);
334
340
};
335
341
llvm::SmallVector<mlir::Value> resultLengths;
342
+ mlir::Value arrayResultShape;
343
+ hlfir::EvaluateInMemoryOp evaluateInMemory;
336
344
auto allocatedResult = [&]() -> std::optional<fir::ExtendedValue> {
337
345
llvm::SmallVector<mlir::Value> extents;
338
346
llvm::SmallVector<mlir::Value> lengths;
@@ -366,6 +374,18 @@ std::pair<fir::ExtendedValue, bool> Fortran::lower::genCallOpAndResult(
366
374
resultLengths = lengths;
367
375
}
368
376
377
+ if (!extents.empty ())
378
+ arrayResultShape = builder.genShape (loc, extents);
379
+
380
+ if (isExprCall) {
381
+ mlir::Type exprType = hlfir::getExprType (type);
382
+ evaluateInMemory = builder.create <hlfir::EvaluateInMemoryOp>(
383
+ loc, exprType, arrayResultShape, resultLengths);
384
+ builder.setInsertionPointToStart (&evaluateInMemory.getBody ().front ());
385
+ return toExtendedValue (loc, evaluateInMemory.getMemory (), extents,
386
+ lengths);
387
+ }
388
+
369
389
if ((!extents.empty () || !lengths.empty ()) && !isElemental) {
370
390
// Note: in the elemental context, the alloca ownership inside the
371
391
// elemental region is implicit, and later pass in lowering (stack
@@ -384,8 +404,7 @@ std::pair<fir::ExtendedValue, bool> Fortran::lower::genCallOpAndResult(
384
404
if (mustPopSymMap)
385
405
symMap.popScope ();
386
406
387
- // Place allocated result or prepare the fir.save_result arguments.
388
- mlir::Value arrayResultShape;
407
+ // Place allocated result
389
408
if (allocatedResult) {
390
409
if (std::optional<Fortran::lower::CallInterface<
391
410
Fortran::lower::CallerInterface>::PassedEntity>
@@ -399,16 +418,6 @@ std::pair<fir::ExtendedValue, bool> Fortran::lower::genCallOpAndResult(
399
418
else
400
419
fir::emitFatalError (
401
420
loc, " only expect character scalar result to be passed by ref" );
402
- } else {
403
- assert (caller.mustSaveResult ());
404
- arrayResultShape = allocatedResult->match (
405
- [&](const fir::CharArrayBoxValue &) {
406
- return builder.createShape (loc, *allocatedResult);
407
- },
408
- [&](const fir::ArrayBoxValue &) {
409
- return builder.createShape (loc, *allocatedResult);
410
- },
411
- [&](const auto &) { return mlir::Value{}; });
412
421
}
413
422
}
414
423
@@ -642,13 +651,39 @@ std::pair<fir::ExtendedValue, bool> Fortran::lower::genCallOpAndResult(
642
651
callResult = call.getResult (0 );
643
652
}
644
653
654
+ std::optional<Fortran::evaluate::DynamicType> retTy =
655
+ caller.getCallDescription ().proc ().GetType ();
656
+ // With HLFIR lowering, isElemental must be set to true
657
+ // if we are producing an elemental call. In this case,
658
+ // the elemental results must not be destroyed, instead,
659
+ // the resulting array result will be finalized/destroyed
660
+ // as needed by hlfir.destroy.
661
+ const bool mustFinalizeResult =
662
+ !isElemental && callSiteType.getNumResults () > 0 &&
663
+ !fir::isPointerType (callSiteType.getResult (0 )) && retTy.has_value () &&
664
+ (retTy->category () == Fortran::common::TypeCategory::Derived ||
665
+ retTy->IsPolymorphic () || retTy->IsUnlimitedPolymorphic ());
666
+
645
667
if (caller.mustSaveResult ()) {
646
668
assert (allocatedResult.has_value ());
647
669
builder.create <fir::SaveResultOp>(loc, callResult,
648
670
fir::getBase (*allocatedResult),
649
671
arrayResultShape, resultLengths);
650
672
}
651
673
674
+ if (evaluateInMemory) {
675
+ builder.setInsertionPointAfter (evaluateInMemory);
676
+ mlir::Value expr = evaluateInMemory.getResult ();
677
+ fir::FirOpBuilder *bldr = &converter.getFirOpBuilder ();
678
+ if (!isElemental)
679
+ stmtCtx.attachCleanup ([bldr, loc, expr, mustFinalizeResult]() {
680
+ bldr->create <hlfir::DestroyOp>(loc, expr,
681
+ /* finalize=*/ mustFinalizeResult);
682
+ });
683
+ return {LoweredResult{hlfir::EntityWithAttributes{expr}},
684
+ mustFinalizeResult};
685
+ }
686
+
652
687
if (allocatedResult) {
653
688
// The result must be optionally destroyed (if it is of a derived type
654
689
// that may need finalization or deallocation of the components).
@@ -679,17 +714,7 @@ std::pair<fir::ExtendedValue, bool> Fortran::lower::genCallOpAndResult(
679
714
// derived-type.
680
715
// For polymorphic and unlimited polymorphic enities call the runtime
681
716
// in any cases.
682
- std::optional<Fortran::evaluate::DynamicType> retTy =
683
- caller.getCallDescription ().proc ().GetType ();
684
- // With HLFIR lowering, isElemental must be set to true
685
- // if we are producing an elemental call. In this case,
686
- // the elemental results must not be destroyed, instead,
687
- // the resulting array result will be finalized/destroyed
688
- // as needed by hlfir.destroy.
689
- if (!isElemental && !fir::isPointerType (funcType.getResults ()[0 ]) &&
690
- retTy &&
691
- (retTy->category () == Fortran::common::TypeCategory::Derived ||
692
- retTy->IsPolymorphic () || retTy->IsUnlimitedPolymorphic ())) {
717
+ if (mustFinalizeResult) {
693
718
if (retTy->IsPolymorphic () || retTy->IsUnlimitedPolymorphic ()) {
694
719
auto *bldr = &converter.getFirOpBuilder ();
695
720
stmtCtx.attachCleanup ([bldr, loc, allocatedResult]() {
@@ -715,12 +740,13 @@ std::pair<fir::ExtendedValue, bool> Fortran::lower::genCallOpAndResult(
715
740
}
716
741
}
717
742
}
718
- return {*allocatedResult, resultIsFinalized};
743
+ return {LoweredResult{ *allocatedResult} , resultIsFinalized};
719
744
}
720
745
721
746
// subroutine call
722
747
if (!resultType)
723
- return {fir::ExtendedValue{mlir::Value{}}, /* resultIsFinalized=*/ false };
748
+ return {LoweredResult{fir::ExtendedValue{mlir::Value{}}},
749
+ /* resultIsFinalized=*/ false };
724
750
725
751
// For now, Fortran return values are implemented with a single MLIR
726
752
// function return value.
@@ -734,10 +760,13 @@ std::pair<fir::ExtendedValue, bool> Fortran::lower::genCallOpAndResult(
734
760
mlir::dyn_cast<fir::CharacterType>(funcType.getResults ()[0 ]);
735
761
mlir::Value len = builder.createIntegerConstant (
736
762
loc, builder.getCharacterLengthType (), charTy.getLen ());
737
- return {fir::CharBoxValue{callResult, len}, /* resultIsFinalized=*/ false };
763
+ return {
764
+ LoweredResult{fir::ExtendedValue{fir::CharBoxValue{callResult, len}}},
765
+ /* resultIsFinalized=*/ false };
738
766
}
739
767
740
- return {callResult, /* resultIsFinalized=*/ false };
768
+ return {LoweredResult{fir::ExtendedValue{callResult}},
769
+ /* resultIsFinalized=*/ false };
741
770
}
742
771
743
772
static hlfir::EntityWithAttributes genStmtFunctionRef (
@@ -1661,19 +1690,25 @@ genUserCall(Fortran::lower::PreparedActualArguments &loweredActuals,
1661
1690
// Prepare lowered arguments according to the interface
1662
1691
// and map the lowered values to the dummy
1663
1692
// arguments.
1664
- auto [result , resultIsFinalized] = Fortran::lower::genCallOpAndResult (
1693
+ auto [loweredResult , resultIsFinalized] = Fortran::lower::genCallOpAndResult (
1665
1694
loc, callContext.converter , callContext.symMap , callContext.stmtCtx ,
1666
1695
caller, callSiteType, callContext.resultType ,
1667
1696
callContext.isElementalProcWithArrayArgs ());
1668
- // For procedure pointer function result, just return the call.
1669
- if (callContext.resultType &&
1670
- mlir::isa<fir::BoxProcType>(*callContext.resultType ))
1671
- return hlfir::EntityWithAttributes (fir::getBase (result));
1672
1697
1673
1698
// / Clean-up associations and copy-in.
1674
1699
for (auto cleanUp : callCleanUps)
1675
1700
cleanUp.genCleanUp (loc, builder);
1676
1701
1702
+ if (auto *entity = std::get_if<hlfir::EntityWithAttributes>(&loweredResult))
1703
+ return *entity;
1704
+
1705
+ auto &result = std::get<fir::ExtendedValue>(loweredResult);
1706
+
1707
+ // For procedure pointer function result, just return the call.
1708
+ if (callContext.resultType &&
1709
+ mlir::isa<fir::BoxProcType>(*callContext.resultType ))
1710
+ return hlfir::EntityWithAttributes (fir::getBase (result));
1711
+
1677
1712
if (!fir::getBase (result))
1678
1713
return std::nullopt; // subroutine call.
1679
1714
0 commit comments