@@ -221,6 +221,25 @@ bool hlfir::Entity::mayHaveNonDefaultLowerBounds() const {
221
221
return true ;
222
222
}
223
223
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 (!isVariable ())
232
+ return false ;
233
+ // TODO: introduce a fir type to better identify optionals.
234
+ if (mlir::Operation *op = traverseConverts (getDefiningOp ())) {
235
+ if (auto varIface = llvm::dyn_cast<fir::FortranVariableOpInterface>(op))
236
+ return varIface.isOptional ();
237
+ return !llvm::isa<fir::AllocaOp, fir::AllocMemOp, fir::ReboxOp,
238
+ fir::EmboxOp, fir::LoadOp>(op);
239
+ }
240
+ return true ;
241
+ }
242
+
224
243
fir::FortranVariableOpInterface
225
244
hlfir::genDeclare (mlir::Location loc, fir::FirOpBuilder &builder,
226
245
const fir::ExtendedValue &exv, llvm::StringRef name,
@@ -963,9 +982,69 @@ llvm::SmallVector<mlir::Value> hlfir::genLoopNestWithReductions(
963
982
return outerLoop->getResults ();
964
983
}
965
984
985
+ template <typename Lambda>
986
+ static fir::ExtendedValue
987
+ conditionallyEvaluate (mlir::Location loc, fir::FirOpBuilder &builder,
988
+ mlir::Value condition, const Lambda &genIfTrue) {
989
+ mlir::OpBuilder::InsertPoint insertPt = builder.saveInsertionPoint ();
990
+
991
+ // Evaluate in some region that will be moved into the actual ifOp (the actual
992
+ // ifOp can only be created when the result types are known).
993
+ auto badIfOp = builder.create <fir::IfOp>(loc, condition.getType (), condition,
994
+ /* withElseRegion=*/ false );
995
+ mlir::Block *preparationBlock = &badIfOp.getThenRegion ().front ();
996
+ builder.setInsertionPointToStart (preparationBlock);
997
+ fir::ExtendedValue result = genIfTrue ();
998
+ fir::ResultOp resultOp = result.match (
999
+ [&](const fir::CharBoxValue &box) -> fir::ResultOp {
1000
+ return builder.create <fir::ResultOp>(
1001
+ loc, mlir::ValueRange{box.getAddr (), box.getLen ()});
1002
+ },
1003
+ [&](const mlir::Value &addr) -> fir::ResultOp {
1004
+ return builder.create <fir::ResultOp>(loc, addr);
1005
+ },
1006
+ [&](const auto &) -> fir::ResultOp {
1007
+ TODO (loc, " unboxing non scalar optional fir.box" );
1008
+ });
1009
+ builder.restoreInsertionPoint (insertPt);
1010
+
1011
+ // Create actual fir.if operation.
1012
+ auto ifOp =
1013
+ builder.create <fir::IfOp>(loc, resultOp->getOperandTypes (), condition,
1014
+ /* withElseRegion=*/ true );
1015
+ // Move evaluation into Then block,
1016
+ preparationBlock->moveBefore (&ifOp.getThenRegion ().back ());
1017
+ ifOp.getThenRegion ().back ().erase ();
1018
+ // Create absent result in the Else block.
1019
+ builder.setInsertionPointToStart (&ifOp.getElseRegion ().front ());
1020
+ llvm::SmallVector<mlir::Value> absentValues;
1021
+ for (mlir::Type resTy : ifOp->getResultTypes ()) {
1022
+ if (fir::isa_ref_type (resTy) || fir::isa_box_type (resTy))
1023
+ absentValues.emplace_back (builder.create <fir::AbsentOp>(loc, resTy));
1024
+ else
1025
+ absentValues.emplace_back (builder.create <fir::ZeroOp>(loc, resTy));
1026
+ }
1027
+ builder.create <fir::ResultOp>(loc, absentValues);
1028
+ badIfOp->erase ();
1029
+
1030
+ // Build fir::ExtendedValue from the result values.
1031
+ builder.setInsertionPointAfter (ifOp);
1032
+ return result.match (
1033
+ [&](const fir::CharBoxValue &box) -> fir::ExtendedValue {
1034
+ return fir::CharBoxValue{ifOp.getResult (0 ), ifOp.getResult (1 )};
1035
+ },
1036
+ [&](const mlir::Value &) -> fir::ExtendedValue {
1037
+ return ifOp.getResult (0 );
1038
+ },
1039
+ [&](const auto &) -> fir::ExtendedValue {
1040
+ TODO (loc, " unboxing non scalar optional fir.box" );
1041
+ });
1042
+ }
1043
+
966
1044
static fir::ExtendedValue translateVariableToExtendedValue (
967
1045
mlir::Location loc, fir::FirOpBuilder &builder, hlfir::Entity variable,
968
- bool forceHlfirBase = false , bool contiguousHint = false ) {
1046
+ bool forceHlfirBase = false , bool contiguousHint = false ,
1047
+ bool keepScalarOptionalBoxed = false ) {
969
1048
assert (variable.isVariable () && " must be a variable" );
970
1049
// When going towards FIR, use the original base value to avoid
971
1050
// introducing descriptors at runtime when they are not required.
@@ -984,14 +1063,33 @@ static fir::ExtendedValue translateVariableToExtendedValue(
984
1063
const bool contiguous = variable.isSimplyContiguous () || contiguousHint;
985
1064
const bool isAssumedRank = variable.isAssumedRank ();
986
1065
if (!contiguous || variable.isPolymorphic () ||
987
- variable.isDerivedWithLengthParameters () || variable.isOptional () ||
988
- isAssumedRank) {
1066
+ variable.isDerivedWithLengthParameters () || isAssumedRank) {
989
1067
llvm::SmallVector<mlir::Value> nonDefaultLbounds;
990
1068
if (!isAssumedRank)
991
1069
nonDefaultLbounds = getNonDefaultLowerBounds (loc, builder, variable);
992
1070
return fir::BoxValue (base, nonDefaultLbounds,
993
1071
getExplicitTypeParams (variable));
994
1072
}
1073
+ if (variable.mayBeOptional ()) {
1074
+ if (!keepScalarOptionalBoxed && variable.isScalar ()) {
1075
+ mlir::Value isPresent = builder.create <fir::IsPresentOp>(
1076
+ loc, builder.getI1Type (), variable);
1077
+ return conditionallyEvaluate (
1078
+ loc, builder, isPresent, [&]() -> fir::ExtendedValue {
1079
+ mlir::Value base = genVariableRawAddress (loc, builder, variable);
1080
+ if (variable.isCharacter ()) {
1081
+ mlir::Value len =
1082
+ genCharacterVariableLength (loc, builder, variable);
1083
+ return fir::CharBoxValue{base, len};
1084
+ }
1085
+ return base;
1086
+ });
1087
+ }
1088
+ llvm::SmallVector<mlir::Value> nonDefaultLbounds =
1089
+ getNonDefaultLowerBounds (loc, builder, variable);
1090
+ return fir::BoxValue (base, nonDefaultLbounds,
1091
+ getExplicitTypeParams (variable));
1092
+ }
995
1093
// Otherwise, the variable can be represented in a fir::ExtendedValue
996
1094
// without the overhead of a fir.box.
997
1095
base = genVariableRawAddress (loc, builder, variable);
@@ -1035,10 +1133,12 @@ hlfir::translateToExtendedValue(mlir::Location loc, fir::FirOpBuilder &builder,
1035
1133
1036
1134
std::pair<fir::ExtendedValue, std::optional<hlfir::CleanupFunction>>
1037
1135
hlfir::translateToExtendedValue (mlir::Location loc, fir::FirOpBuilder &builder,
1038
- hlfir::Entity entity, bool contiguousHint) {
1136
+ hlfir::Entity entity, bool contiguousHint,
1137
+ bool keepScalarOptionalBoxed) {
1039
1138
if (entity.isVariable ())
1040
1139
return {translateVariableToExtendedValue (loc, builder, entity, false ,
1041
- contiguousHint),
1140
+ contiguousHint,
1141
+ keepScalarOptionalBoxed),
1042
1142
std::nullopt};
1043
1143
1044
1144
if (entity.isProcedure ()) {
@@ -1094,7 +1194,9 @@ hlfir::convertToBox(mlir::Location loc, fir::FirOpBuilder &builder,
1094
1194
if (entity.isProcedurePointer ())
1095
1195
entity = hlfir::derefPointersAndAllocatables (loc, builder, entity);
1096
1196
1097
- auto [exv, cleanup] = translateToExtendedValue (loc, builder, entity);
1197
+ auto [exv, cleanup] =
1198
+ translateToExtendedValue (loc, builder, entity, /* contiguousHint=*/ false ,
1199
+ /* keepScalarOptionalBoxed=*/ true );
1098
1200
// Procedure entities should not go through createBoxValue that embox
1099
1201
// object entities. Return the fir.boxproc directly.
1100
1202
if (entity.isProcedure ())
0 commit comments