@@ -469,7 +469,7 @@ class MinMaxlocAsElementalConverter : public ReductionAsElementalConverter {
469469 // * 1 boolean indicating whether it is the first time
470470 // the mask is true.
471471 //
472- // If precomputeFirst () returns true , then the boolean loop-carried
472+ // If useIsFirst () returns false , then the boolean loop-carried
473473 // value is not used.
474474 static constexpr unsigned maxNumReductions = Fortran::common::maxRank + 2 ;
475475 static constexpr bool isMax = std::is_same_v<T, hlfir::MaxlocOp>;
@@ -523,7 +523,7 @@ class MinMaxlocAsElementalConverter : public ReductionAsElementalConverter {
523523
524524 void
525525 checkReductions (const llvm::SmallVectorImpl<mlir::Value> &reductions) const {
526- if (precomputeFirst ())
526+ if (! useIsFirst ())
527527 assert (reductions.size () == getNumCoors () + 1 &&
528528 " invalid number of reductions for MINLOC/MAXLOC" );
529529 else
@@ -540,15 +540,24 @@ class MinMaxlocAsElementalConverter : public ReductionAsElementalConverter {
540540 mlir::Value
541541 getIsFirst (const llvm::SmallVectorImpl<mlir::Value> &reductions) const {
542542 checkReductions (reductions);
543- assert (! precomputeFirst () && " IsFirst predicate must not be used" );
543+ assert (useIsFirst () && " IsFirst predicate must not be used" );
544544 return reductions[getNumCoors () + 1 ];
545545 }
546546
547- // Return true iff the reductions can be initialized
548- // by reading the first element of the array (or its section).
549- // If it returns false, then we use an auxiliary boolean
550- // to identify the very first reduction update.
551- bool precomputeFirst () const { return !getMask (); }
547+ // Return true iff the input can contain NaNs, and they should be
548+ // honored, such that all-NaNs input must produce the location
549+ // of the first unmasked NaN.
550+ bool honorNans () const {
551+ return !static_cast <bool >(getFastMath () & mlir::arith::FastMathFlags::nnan);
552+ }
553+
554+ // Return true iff we have to use the loop-carried IsFirst predicate.
555+ // If there is no mask, we can initialize the reductions using
556+ // the first elements of the input.
557+ // If NaNs are not honored, we can initialize the starting MIN/MAX
558+ // value to +/-LARGEST; the coordinates are guaranteed to be updated
559+ // properly for non-empty input without NaNs.
560+ bool useIsFirst () const { return getMask () && honorNans (); }
552561};
553562
554563template <typename T>
@@ -557,9 +566,10 @@ MinMaxlocAsElementalConverter<T>::genReductionInitValues(
557566 mlir::ValueRange oneBasedIndices,
558567 const llvm::SmallVectorImpl<mlir::Value> &extents) {
559568 fir::IfOp ifOp;
560- if (precomputeFirst ()) {
569+ if (! useIsFirst () && honorNans ()) {
561570 // Check if we can load the value of the first element in the array
562571 // or its section (for partial reduction).
572+ assert (!getMask () && " cannot fetch first element when mask is present" );
563573 assert (extents.size () == getNumCoors () &&
564574 " wrong number of extents for MINLOC/MAXLOC reduction" );
565575 mlir::Value isNotEmpty = genIsNotEmptyArrayExtents (loc, builder, extents);
@@ -600,7 +610,7 @@ MinMaxlocAsElementalConverter<T>::genReductionInitValues(
600610 builder.create <fir::ResultOp>(loc, result);
601611 builder.setInsertionPointAfter (ifOp);
602612 result = ifOp.getResults ();
603- } else {
613+ } else if ( useIsFirst ()) {
604614 // Initial value for isFirst predicate. It is switched to false,
605615 // when the reduction update dynamically happens inside the reduction
606616 // loop.
@@ -621,7 +631,7 @@ MinMaxlocAsElementalConverter<T>::reduceOneElement(
621631 hlfir::loadElementAt (loc, builder, array, oneBasedIndices);
622632 mlir::Value cmp = genMinMaxComparison<isMax>(loc, builder, elementValue,
623633 getCurrentMinMax (currentValue));
624- if (! precomputeFirst ()) {
634+ if (useIsFirst ()) {
625635 // If isFirst is true, then do the reduction update regardless
626636 // of the FP comparison.
627637 cmp =
@@ -652,7 +662,7 @@ MinMaxlocAsElementalConverter<T>::reduceOneElement(
652662 loc, cmp, elementValue, getCurrentMinMax (currentValue));
653663 newIndices.push_back (newMinMax);
654664
655- if (! precomputeFirst ()) {
665+ if (useIsFirst ()) {
656666 mlir::Value newIsFirst = builder.createBool (loc, false );
657667 newIndices.push_back (newIsFirst);
658668 }
@@ -746,7 +756,7 @@ class MinMaxvalAsElementalConverter
746756 //
747757 // The boolean flag is used to replace the initial value
748758 // with the first input element even if it is NaN.
749- // If precomputeFirst () returns true , then the boolean loop-carried
759+ // If useIsFirst () returns false , then the boolean loop-carried
750760 // value is not used.
751761 static constexpr bool isMax = std::is_same_v<T, hlfir::MaxvalOp>;
752762 using Base = NumericReductionAsElementalConverterBase<T>;
@@ -781,13 +791,13 @@ class MinMaxvalAsElementalConverter
781791 mlir::Value currentMinMax = getCurrentMinMax (currentValue);
782792 mlir::Value cmp =
783793 genMinMaxComparison<isMax>(loc, builder, elementValue, currentMinMax);
784- if (! precomputeFirst ())
794+ if (useIsFirst ())
785795 cmp = builder.create <mlir::arith::OrIOp>(loc, cmp,
786796 getIsFirst (currentValue));
787797 mlir::Value newMinMax = builder.create <mlir::arith::SelectOp>(
788798 loc, cmp, elementValue, currentMinMax);
789799 result.push_back (newMinMax);
790- if (! precomputeFirst ())
800+ if (useIsFirst ())
791801 result.push_back (builder.createBool (loc, false ));
792802 return result;
793803 }
@@ -813,17 +823,25 @@ class MinMaxvalAsElementalConverter
813823 mlir::Value
814824 getIsFirst (const llvm::SmallVectorImpl<mlir::Value> &reductions) const {
815825 this ->checkReductions (reductions);
816- assert (! precomputeFirst () && " IsFirst predicate must not be used" );
826+ assert (useIsFirst () && " IsFirst predicate must not be used" );
817827 return reductions[1 ];
818828 }
819829
820- // Return true iff the reductions can be initialized
821- // by reading the first element of the array (or its section).
822- // If it returns false, then we use an auxiliary boolean
823- // to identify the very first reduction update.
824- bool precomputeFirst () const { return !this ->getMask (); }
830+ // Return true iff the input can contain NaNs, and they should be
831+ // honored, such that all-NaNs input must produce NaN result.
832+ bool honorNans () const {
833+ return !static_cast <bool >(this ->getFastMath () &
834+ mlir::arith::FastMathFlags::nnan);
835+ }
836+
837+ // Return true iff we have to use the loop-carried IsFirst predicate.
838+ // If there is no mask, we can initialize the reductions using
839+ // the first elements of the input.
840+ // If NaNs are not honored, we can initialize the starting MIN/MAX
841+ // value to +/-LARGEST.
842+ bool useIsFirst () const { return this ->getMask () && honorNans (); }
825843
826- std::size_t getNumReductions () const { return precomputeFirst () ? 1 : 2 ; }
844+ std::size_t getNumReductions () const { return useIsFirst () ? 2 : 1 ; }
827845};
828846
829847template <typename T>
@@ -836,12 +854,14 @@ MinMaxvalAsElementalConverter<T>::genReductionInitValues(
836854 mlir::Location loc = this ->loc ;
837855
838856 fir::IfOp ifOp;
839- if (precomputeFirst ()) {
857+ if (! useIsFirst () && honorNans ()) {
840858 // Check if we can load the value of the first element in the array
841859 // or its section (for partial reduction).
842- assert (extents.size () == this ->isTotalReduction ()
843- ? this ->getSourceRank ()
844- : 1u && " wrong number of extents for MINVAL/MAXVAL reduction" );
860+ assert (!this ->getMask () &&
861+ " cannot fetch first element when mask is present" );
862+ assert (extents.size () ==
863+ (this ->isTotalReduction () ? this ->getSourceRank () : 1u ) &&
864+ " wrong number of extents for MINVAL/MAXVAL reduction" );
845865 mlir::Value isNotEmpty = genIsNotEmptyArrayExtents (loc, builder, extents);
846866 llvm::SmallVector<mlir::Value> indices = genFirstElementIndicesForReduction (
847867 loc, builder, this ->isTotalReduction (), this ->getConstDim (),
@@ -867,7 +887,7 @@ MinMaxvalAsElementalConverter<T>::genReductionInitValues(
867887 builder.create <fir::ResultOp>(loc, result);
868888 builder.setInsertionPointAfter (ifOp);
869889 result = ifOp.getResults ();
870- } else {
890+ } else if ( useIsFirst ()) {
871891 // Initial value for isFirst predicate. It is switched to false,
872892 // when the reduction update dynamically happens inside the reduction
873893 // loop.
0 commit comments