@@ -221,6 +221,24 @@ bool hlfir::Entity::mayHaveNonDefaultLowerBounds() const {
221221 return true ;
222222}
223223
224+ mlir::Operation* traverseConverts (mlir::Operation *op) {
225+ while (auto convert = llvm::dyn_cast_or_null<fir::ConvertOp>(op))
226+ op = convert.getValue ().getDefiningOp ();
227+ return op;
228+ }
229+
230+ bool hlfir::Entity::mayBeOptional () const {
231+ if (auto varIface = getIfVariableInterface ())
232+ return varIface.isOptional ();
233+ if (!isVariable ())
234+ return false ;
235+ // TODO: introduce a fir type to better identify optionals.
236+ if (mlir::Operation* op = traverseConverts (getDefiningOp ()))
237+ return !llvm::isa<fir::AllocaOp, fir::AllocMemOp, fir::ReboxOp,
238+ fir::EmboxOp>(op);
239+ return true ;
240+ }
241+
224242fir::FortranVariableOpInterface
225243hlfir::genDeclare (mlir::Location loc, fir::FirOpBuilder &builder,
226244 const fir::ExtendedValue &exv, llvm::StringRef name,
@@ -963,9 +981,68 @@ llvm::SmallVector<mlir::Value> hlfir::genLoopNestWithReductions(
963981 return outerLoop->getResults ();
964982}
965983
984+ template <typename Lambda>
985+ static fir::ExtendedValue
986+ conditionnalyEvaluate (mlir::Location loc, fir::FirOpBuilder &builder,
987+ mlir::Value condition, const Lambda &genIfTrue) {
988+ mlir::OpBuilder::InsertPoint insertPt = builder.saveInsertionPoint ();
989+
990+ // Evaluate in some region that will be moved into the actual ifOp (the actual
991+ // ifOp can only be created when the result types are known).
992+ auto badIfOp = builder.create <fir::IfOp>(loc, condition.getType (), condition,
993+ /* withElseRegion=*/ false );
994+ mlir::Block *preparationBlock = &badIfOp.getThenRegion ().front ();
995+ builder.setInsertionPointToStart (preparationBlock);
996+ fir::ExtendedValue result = genIfTrue ();
997+ fir::ResultOp resultOp = result.match (
998+ [&](const fir::CharBoxValue &box) -> fir::ResultOp {
999+ return builder.create <fir::ResultOp>(
1000+ loc, mlir::ValueRange{box.getAddr (), box.getLen ()});
1001+ },
1002+ [&](const mlir::Value &addr) -> fir::ResultOp {
1003+ return builder.create <fir::ResultOp>(loc, addr);
1004+ },
1005+ [&](const auto &) -> fir::ResultOp {
1006+ TODO (loc, " unboxing non scalar optional fir.box" );
1007+ });
1008+ builder.restoreInsertionPoint (insertPt);
1009+
1010+ // Create actual fir.if operation.
1011+ auto ifOp =
1012+ builder.create <fir::IfOp>(loc, resultOp->getOperandTypes (), condition,
1013+ /* withElseRegion=*/ true );
1014+ // Move evaluation into Then block,
1015+ preparationBlock->moveBefore (&ifOp.getThenRegion ().back ());
1016+ ifOp.getThenRegion ().back ().erase ();
1017+ // Create absent result in the Else block.
1018+ builder.setInsertionPointToStart (&ifOp.getElseRegion ().front ());
1019+ llvm::SmallVector<mlir::Value> absentValues;
1020+ for (mlir::Type resTy : ifOp->getResultTypes ()) {
1021+ if (fir::isa_ref_type (resTy) || fir::isa_box_type (resTy))
1022+ absentValues.emplace_back (builder.create <fir::AbsentOp>(loc, resTy));
1023+ else
1024+ absentValues.emplace_back (builder.create <fir::ZeroOp>(loc, resTy));
1025+ }
1026+ builder.create <fir::ResultOp>(loc, absentValues);
1027+ badIfOp->erase ();
1028+
1029+ // Build fir::ExtendedValue from the result values.
1030+ builder.setInsertionPointAfter (ifOp);
1031+ return result.match (
1032+ [&](const fir::CharBoxValue &box) -> fir::ExtendedValue {
1033+ return fir::CharBoxValue{ifOp.getResult (0 ), ifOp.getResult (1 )};
1034+ },
1035+ [&](const mlir::Value &) -> fir::ExtendedValue {
1036+ return ifOp.getResult (0 );
1037+ },
1038+ [&](const auto &) -> fir::ExtendedValue {
1039+ TODO (loc, " unboxing non scalar optional fir.box" );
1040+ });
1041+ }
1042+
9661043static fir::ExtendedValue translateVariableToExtendedValue (
9671044 mlir::Location loc, fir::FirOpBuilder &builder, hlfir::Entity variable,
968- bool forceHlfirBase = false , bool contiguousHint = false ) {
1045+ bool forceHlfirBase = false , bool contiguousHint = false , bool keepScalarOptionalBoxed = false ) {
9691046 assert (variable.isVariable () && " must be a variable" );
9701047 // When going towards FIR, use the original base value to avoid
9711048 // introducing descriptors at runtime when they are not required.
@@ -984,14 +1061,33 @@ static fir::ExtendedValue translateVariableToExtendedValue(
9841061 const bool contiguous = variable.isSimplyContiguous () || contiguousHint;
9851062 const bool isAssumedRank = variable.isAssumedRank ();
9861063 if (!contiguous || variable.isPolymorphic () ||
987- variable.isDerivedWithLengthParameters () || variable. isOptional () ||
1064+ variable.isDerivedWithLengthParameters () ||
9881065 isAssumedRank) {
9891066 llvm::SmallVector<mlir::Value> nonDefaultLbounds;
9901067 if (!isAssumedRank)
9911068 nonDefaultLbounds = getNonDefaultLowerBounds (loc, builder, variable);
9921069 return fir::BoxValue (base, nonDefaultLbounds,
9931070 getExplicitTypeParams (variable));
9941071 }
1072+ if (variable.mayBeOptional ()) {
1073+ if (!keepScalarOptionalBoxed && variable.isScalar ()) {
1074+ mlir::Value isPresent = builder.create <fir::IsPresentOp>(
1075+ loc, builder.getI1Type (), variable);
1076+ return conditionnalyEvaluate (
1077+ loc, builder, isPresent, [&]() -> fir::ExtendedValue {
1078+ mlir::Value base = genVariableRawAddress (loc, builder, variable);
1079+ if (variable.isCharacter ()) {
1080+ mlir::Value len =
1081+ genCharacterVariableLength (loc, builder, variable);
1082+ return fir::CharBoxValue{base, len};
1083+ }
1084+ return base;
1085+ });
1086+ }
1087+ llvm::SmallVector<mlir::Value> nonDefaultLbounds = getNonDefaultLowerBounds (loc, builder, variable);
1088+ return fir::BoxValue (base, nonDefaultLbounds,
1089+ getExplicitTypeParams (variable));
1090+ }
9951091 // Otherwise, the variable can be represented in a fir::ExtendedValue
9961092 // without the overhead of a fir.box.
9971093 base = genVariableRawAddress (loc, builder, variable);
@@ -1035,10 +1131,12 @@ hlfir::translateToExtendedValue(mlir::Location loc, fir::FirOpBuilder &builder,
10351131
10361132std::pair<fir::ExtendedValue, std::optional<hlfir::CleanupFunction>>
10371133hlfir::translateToExtendedValue (mlir::Location loc, fir::FirOpBuilder &builder,
1038- hlfir::Entity entity, bool contiguousHint) {
1134+ hlfir::Entity entity, bool contiguousHint,
1135+ bool keepScalarOptionalBoxed) {
10391136 if (entity.isVariable ())
10401137 return {translateVariableToExtendedValue (loc, builder, entity, false ,
1041- contiguousHint),
1138+ contiguousHint,
1139+ keepScalarOptionalBoxed),
10421140 std::nullopt };
10431141
10441142 if (entity.isProcedure ()) {
0 commit comments