Index: flang/lib/Optimizer/Transforms/SimplifyIntrinsics.cpp =================================================================== --- flang/lib/Optimizer/Transforms/SimplifyIntrinsics.cpp +++ flang/lib/Optimizer/Transforms/SimplifyIntrinsics.cpp @@ -617,8 +617,18 @@ auto genBodyOp = [](fir::FirOpBuilder builder, mlir::Location loc, mlir::Type elementType, mlir::Value elem1, mlir::Value elem2) -> mlir::Value { - if (elementType.isa()) - return builder.create(loc, elem1, elem2); + if (elementType.isa()) { + // arith.maxf later converted to llvm.intr.maxnum does not work + // correctly for NaNs and -0.0 (see maxnum/minnum pattern matching + // in LLVM's InstCombine pass). Moreover, llvm.intr.maxnum + // for F128 operands is lowered into fmaxl call by LLVM. + // This libm function may not work properly for F128 arguments + // on targets where long double is not F128. It is an LLVM issue, + // but we just use normal select here to resolve all the cases. + auto compare = builder.create( + loc, mlir::arith::CmpFPredicate::OGT, elem1, elem2); + return builder.create(loc, compare, elem1, elem2); + } if (elementType.isa()) return builder.create(loc, elem1, elem2); Index: flang/test/Transforms/simplifyintrinsics.fir =================================================================== --- flang/test/Transforms/simplifyintrinsics.fir +++ flang/test/Transforms/simplifyintrinsics.fir @@ -899,7 +899,8 @@ // CHECK: %[[RES:.*]] = fir.do_loop %[[ITER:.*]] = %[[CINDEX_0]] to %[[EXTENT]] step %[[CINDEX_1]] iter_args(%[[MAX]] = %[[NEG_DBL_MAX]]) -> (f64) { // CHECK: %[[ITEM:.*]] = fir.coordinate_of %[[ARR_BOX_F64]], %[[ITER]] : (!fir.box>, index) -> !fir.ref // CHECK: %[[ITEM_VAL:.*]] = fir.load %[[ITEM]] : !fir.ref -// CHECK: %[[NEW_MAX:.*]] = arith.maxf %[[ITEM_VAL]], %[[MAX]] : f64 +// CHECK: %[[CMP:.*]] = arith.cmpf ogt, %[[ITEM_VAL]], %[[MAX]] : f64 +// CHECK: %[[NEW_MAX:.*]] = arith.select %[[CMP]], %[[ITEM_VAL]], %[[MAX]] : f64 // CHECK: fir.result %[[NEW_MAX]] : f64 // CHECK: } // CHECK: return %[[RES]] : f64