@@ -69,6 +69,11 @@ class HlfirTransformationalIntrinsic {
6969 mlir::Value loadBoxAddress (
7070 const std::optional<Fortran::lower::PreparedActualArgument> &arg);
7171
72+ mlir::Value
73+ loadTrivialScalar (const Fortran::lower::PreparedActualArgument &arg);
74+
75+ mlir::Value loadOptionalValue (Fortran::lower::PreparedActualArgument &arg);
76+
7277 void addCleanup (std::optional<hlfir::CleanupFunction> cleanup) {
7378 if (cleanup)
7479 cleanupFns.emplace_back (std::move (*cleanup));
@@ -204,6 +209,17 @@ class HlfirReshapeLowering : public HlfirTransformationalIntrinsic {
204209 mlir::Type stmtResultType) override ;
205210};
206211
212+ class HlfirIndexLowering : public HlfirTransformationalIntrinsic {
213+ public:
214+ using HlfirTransformationalIntrinsic::HlfirTransformationalIntrinsic;
215+
216+ protected:
217+ mlir::Value
218+ lowerImpl (const Fortran::lower::PreparedActualArguments &loweredActuals,
219+ const fir::IntrinsicArgumentLoweringRules *argLowering,
220+ mlir::Type stmtResultType) override ;
221+ };
222+
207223} // namespace
208224
209225mlir::Value HlfirTransformationalIntrinsic::loadBoxAddress (
@@ -239,19 +255,22 @@ mlir::Value HlfirTransformationalIntrinsic::loadBoxAddress(
239255 return boxOrAbsent;
240256}
241257
242- static mlir::Value loadOptionalValue (
243- mlir::Location loc, fir::FirOpBuilder &builder,
244- const std::optional<Fortran::lower::PreparedActualArgument> &arg,
245- hlfir::Entity actual) {
246- if (!arg->handleDynamicOptional ())
247- return hlfir::loadTrivialScalar (loc, builder, actual);
258+ mlir::Value HlfirTransformationalIntrinsic::loadOptionalValue (
259+ Fortran::lower::PreparedActualArgument &arg) {
260+ mlir::Type eleType = arg.getFortranElementType ();
248261
249- mlir::Value isPresent = arg->getIsPresent ();
250- mlir::Type eleType = hlfir::getFortranElementType (actual.getType ());
262+ // For an elemental call, getActual() may produce
263+ // a designator denoting the array element to be passed
264+ // to the subprogram. If the actual array is dynamically
265+ // optional the designator must be generated under
266+ // isPresent check (see also genIntrinsicRefCore).
251267 return builder
252- .genIfOp (loc, {eleType}, isPresent ,
268+ .genIfOp (loc, {eleType}, arg. getIsPresent () ,
253269 /* withElseRegion=*/ true )
254270 .genThen ([&]() {
271+ hlfir::Entity actual = arg.getActual (loc, builder);
272+ assert (eleType == actual.getFortranElementType () &&
273+ " result type mismatch in genOptionalValue" );
255274 assert (actual.isScalar () && fir::isa_trivial (eleType) &&
256275 " must be a numerical or logical scalar" );
257276 hlfir::Entity val = hlfir::loadTrivialScalar (loc, builder, actual);
@@ -264,6 +283,12 @@ static mlir::Value loadOptionalValue(
264283 .getResults ()[0 ];
265284}
266285
286+ mlir::Value HlfirTransformationalIntrinsic::loadTrivialScalar (
287+ const Fortran::lower::PreparedActualArgument &arg) {
288+ hlfir::Entity actual = arg.getActual (loc, builder);
289+ return hlfir::loadTrivialScalar (loc, builder, actual);
290+ }
291+
267292llvm::SmallVector<mlir::Value> HlfirTransformationalIntrinsic::getOperandVector (
268293 const Fortran::lower::PreparedActualArguments &loweredActuals,
269294 const fir::IntrinsicArgumentLoweringRules *argLowering) {
@@ -277,29 +302,33 @@ llvm::SmallVector<mlir::Value> HlfirTransformationalIntrinsic::getOperandVector(
277302 operands.emplace_back ();
278303 continue ;
279304 }
280- hlfir::Entity actual = arg->getActual (loc, builder);
281305 mlir::Value valArg;
282-
283306 if (!argLowering) {
284- valArg = hlfir::loadTrivialScalar (loc, builder, actual);
285- } else {
286- fir::ArgLoweringRule argRules =
287- fir::lowerIntrinsicArgumentAs (*argLowering, i);
288- if (argRules.lowerAs == fir::LowerIntrinsicArgAs::Box)
289- valArg = loadBoxAddress (arg);
290- else if (!argRules.handleDynamicOptional &&
291- argRules.lowerAs != fir::LowerIntrinsicArgAs::Inquired)
292- valArg = hlfir::derefPointersAndAllocatables (loc, builder, actual);
293- else if (argRules.handleDynamicOptional &&
294- argRules.lowerAs == fir::LowerIntrinsicArgAs::Value)
295- valArg = loadOptionalValue (loc, builder, arg, actual);
296- else if (argRules.handleDynamicOptional )
307+ valArg = loadTrivialScalar (*arg);
308+ operands.emplace_back (valArg);
309+ continue ;
310+ }
311+ fir::ArgLoweringRule argRules =
312+ fir::lowerIntrinsicArgumentAs (*argLowering, i);
313+ if (argRules.lowerAs == fir::LowerIntrinsicArgAs::Box) {
314+ valArg = loadBoxAddress (arg);
315+ } else if (argRules.handleDynamicOptional ) {
316+ if (argRules.lowerAs == fir::LowerIntrinsicArgAs::Value) {
317+ if (arg->handleDynamicOptional ())
318+ valArg = loadOptionalValue (*arg);
319+ else
320+ valArg = loadTrivialScalar (*arg);
321+ } else {
297322 TODO (loc, " hlfir transformational intrinsic dynamically optional "
298323 " argument without box lowering" );
324+ }
325+ } else {
326+ hlfir::Entity actual = arg->getActual (loc, builder);
327+ if (argRules.lowerAs != fir::LowerIntrinsicArgAs::Inquired)
328+ valArg = hlfir::derefPointersAndAllocatables (loc, builder, actual);
299329 else
300330 valArg = actual.getBase ();
301331 }
302-
303332 operands.emplace_back (valArg);
304333 }
305334 return operands;
@@ -513,6 +542,22 @@ mlir::Value HlfirReshapeLowering::lowerImpl(
513542 operands[2 ], operands[3 ]);
514543}
515544
545+ mlir::Value HlfirIndexLowering::lowerImpl (
546+ const Fortran::lower::PreparedActualArguments &loweredActuals,
547+ const fir::IntrinsicArgumentLoweringRules *argLowering,
548+ mlir::Type stmtResultType) {
549+ auto operands = getOperandVector (loweredActuals, argLowering);
550+ // 'kind' optional operand is unused here as it has already been
551+ // translated into result type.
552+ assert (operands.size () == 4 );
553+ mlir::Value substr = operands[1 ];
554+ mlir::Value str = operands[0 ];
555+ mlir::Value back = operands[2 ];
556+ mlir::Value result =
557+ createOp<hlfir::IndexOp>(stmtResultType, substr, str, back);
558+ return result;
559+ }
560+
516561std::optional<hlfir::EntityWithAttributes> Fortran::lower::lowerHlfirIntrinsic (
517562 fir::FirOpBuilder &builder, mlir::Location loc, const std::string &name,
518563 const Fortran::lower::PreparedActualArguments &loweredActuals,
@@ -567,6 +612,10 @@ std::optional<hlfir::EntityWithAttributes> Fortran::lower::lowerHlfirIntrinsic(
567612 if (name == " reshape" )
568613 return HlfirReshapeLowering{builder, loc}.lower (loweredActuals, argLowering,
569614 stmtResultType);
615+ if (name == " index" )
616+ return HlfirIndexLowering{builder, loc}.lower (loweredActuals, argLowering,
617+ stmtResultType);
618+
570619 if (mlir::isa<fir::CharacterType>(stmtResultType)) {
571620 if (name == " min" )
572621 return HlfirCharExtremumLowering{builder, loc,
0 commit comments