diff --git a/flang/include/flang/Optimizer/Builder/Runtime/Numeric.h b/flang/include/flang/Optimizer/Builder/Runtime/Numeric.h index c1a72478e224c..fec8c9906effe 100644 --- a/flang/include/flang/Optimizer/Builder/Runtime/Numeric.h +++ b/flang/include/flang/Optimizer/Builder/Runtime/Numeric.h @@ -30,6 +30,10 @@ mlir::Value genFraction(fir::FirOpBuilder &builder, mlir::Location loc, mlir::Value genMod(fir::FirOpBuilder &builder, mlir::Location loc, mlir::Value a, mlir::Value p); +/// Generate call to Modulo intrinsic runtime routine. +mlir::Value genModulo(fir::FirOpBuilder &builder, mlir::Location loc, + mlir::Value a, mlir::Value p); + /// Generate call to Nearest intrinsic runtime routine. mlir::Value genNearest(fir::FirOpBuilder &builder, mlir::Location loc, mlir::Value x, mlir::Value s); diff --git a/flang/lib/Optimizer/Builder/IntrinsicCall.cpp b/flang/lib/Optimizer/Builder/IntrinsicCall.cpp index 94fcfa3503114..3f9adf67d6a6c 100644 --- a/flang/lib/Optimizer/Builder/IntrinsicCall.cpp +++ b/flang/lib/Optimizer/Builder/IntrinsicCall.cpp @@ -5240,6 +5240,13 @@ mlir::Value IntrinsicLibrary::genModulo(mlir::Type resultType, remainder); } + // F128 arith::RemFOp may be lowered to a runtime call that may be unsupported + // on the target, so generate a call to Fortran Runtime's ModuloReal16. + if (resultType == mlir::FloatType::getF128(builder.getContext())) + return builder.createConvert( + loc, resultType, + fir::runtime::genModulo(builder, loc, args[0], args[1])); + auto remainder = builder.create(loc, args[0], args[1]); mlir::Value zero = builder.createRealZeroConstant(loc, remainder.getType()); auto remainderIsNotZero = builder.create( diff --git a/flang/lib/Optimizer/Builder/Runtime/Numeric.cpp b/flang/lib/Optimizer/Builder/Runtime/Numeric.cpp index b958a30eb6e5b..4dcbd13cb319f 100644 --- a/flang/lib/Optimizer/Builder/Runtime/Numeric.cpp +++ b/flang/lib/Optimizer/Builder/Runtime/Numeric.cpp @@ -118,6 +118,20 @@ struct ForcedMod16 { } }; +/// Placeholder for real*16 version of Modulo Intrinsic +struct ForcedModulo16 { + static constexpr const char *name = ExpandAndQuoteKey(RTNAME(ModuloReal16)); + static constexpr fir::runtime::FuncTypeBuilderFunc getTypeModel() { + return [](mlir::MLIRContext *ctx) { + auto fltTy = mlir::FloatType::getF128(ctx); + auto strTy = fir::ReferenceType::get(mlir::IntegerType::get(ctx, 8)); + auto intTy = mlir::IntegerType::get(ctx, 8 * sizeof(int)); + return mlir::FunctionType::get(ctx, {fltTy, fltTy, strTy, intTy}, + {fltTy}); + }; + } +}; + /// Placeholder for real*10 version of Nearest Intrinsic struct ForcedNearest10 { static constexpr const char *name = ExpandAndQuoteKey(RTNAME(Nearest10)); @@ -323,6 +337,33 @@ mlir::Value fir::runtime::genMod(fir::FirOpBuilder &builder, mlir::Location loc, return builder.create(loc, func, args).getResult(0); } +/// Generate call to Modulo intrinsic runtime routine. +mlir::Value fir::runtime::genModulo(fir::FirOpBuilder &builder, + mlir::Location loc, mlir::Value a, + mlir::Value p) { + mlir::func::FuncOp func; + mlir::Type fltTy = a.getType(); + + if (fltTy != p.getType()) + fir::emitFatalError(loc, "arguments type mismatch in MOD"); + + // MODULO is lowered into math operations in intrinsics lowering, + // so genModulo() should only be used for F128 data type now. + if (fltTy.isF128()) + func = fir::runtime::getRuntimeFunc(loc, builder); + else + fir::intrinsicTypeTODO(builder, fltTy, loc, "MODULO"); + + auto funcTy = func.getFunctionType(); + auto sourceFile = fir::factory::locationToFilename(builder, loc); + auto sourceLine = + fir::factory::locationToLineNo(builder, loc, funcTy.getInput(3)); + auto args = fir::runtime::createArguments(builder, loc, funcTy, a, p, + sourceFile, sourceLine); + + return builder.create(loc, func, args).getResult(0); +} + /// Generate call to Nearest intrinsic runtime routine. mlir::Value fir::runtime::genNearest(fir::FirOpBuilder &builder, mlir::Location loc, mlir::Value x, diff --git a/flang/test/Lower/Intrinsics/modulo.f90 b/flang/test/Lower/Intrinsics/modulo.f90 index 001e307aa077a..383cb34f83c70 100644 --- a/flang/test/Lower/Intrinsics/modulo.f90 +++ b/flang/test/Lower/Intrinsics/modulo.f90 @@ -40,17 +40,6 @@ subroutine modulo_testi(r, a, p) ! CHECK-SAME: %[[arg0:.*]]: !fir.ref{{.*}}, %[[arg1:.*]]: !fir.ref{{.*}}, %[[arg2:.*]]: !fir.ref{{.*}}) { subroutine modulo_testr16(r, a, p) real(16) :: r, a, p - ! CHECK-DAG: %[[a:.*]] = fir.load %[[arg1]] : !fir.ref - ! CHECK-DAG: %[[p:.*]] = fir.load %[[arg2]] : !fir.ref - ! CHECK-DAG: %[[rem:.*]] = arith.remf %[[a]], %[[p]] {{.*}}: f128 - ! CHECK-DAG: %[[zero:.*]] = arith.constant 0.000000e+00 : f128 - ! CHECK-DAG: %[[remNotZero:.*]] = arith.cmpf une, %[[rem]], %[[zero]] {{.*}} : f128 - ! CHECK-DAG: %[[aNeg:.*]] = arith.cmpf olt, %[[a]], %[[zero]] {{.*}} : f128 - ! CHECK-DAG: %[[pNeg:.*]] = arith.cmpf olt, %[[p]], %[[zero]] {{.*}} : f128 - ! CHECK-DAG: %[[signDifferent:.*]] = arith.xori %[[aNeg]], %[[pNeg]] : i1 - ! CHECK-DAG: %[[mustAddP:.*]] = arith.andi %[[remNotZero]], %[[signDifferent]] : i1 - ! CHECK-DAG: %[[remPlusP:.*]] = arith.addf %[[rem]], %[[p]] {{.*}}: f128 - ! CHECK: %[[res:.*]] = arith.select %[[mustAddP]], %[[remPlusP]], %[[rem]] : f128 - ! CHECK: fir.store %[[res]] to %[[arg0]] : !fir.ref + ! CHECK: fir.call @_FortranAModuloReal16({{.*}}){{.*}}: (f128, f128, !fir.ref, i32) -> f128 r = modulo(a, p) end subroutine