aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSlava Zakharin <szakharin@nvidia.com>2022-08-04 12:07:35 -0700
committerSlava Zakharin <szakharin@nvidia.com>2022-08-05 12:53:37 -0700
commit1b9faafe911ef05c893553cb79cb35db063f1bb3 (patch)
tree819e8ecbdecaa9033dbb9f7cc9e42ec878a4fa56
parent75c64c7c4e40ec9bc16d90fee46353628d08d62d (diff)
[flang] Lower MOD to Fortran runtime call.
This change removes dependency on pgmath mod, and also allows Fortran runtime to issue a diagnostic message in case of zero denominator. Differential Revision: https://reviews.llvm.org/D131192
-rw-r--r--flang/include/flang/Optimizer/Builder/Runtime/Numeric.h4
-rw-r--r--flang/lib/Lower/IntrinsicCall.cpp8
-rw-r--r--flang/lib/Optimizer/Builder/Runtime/Numeric.cpp60
-rw-r--r--flang/test/Lower/Intrinsics/mod.f9054
4 files changed, 121 insertions, 5 deletions
diff --git a/flang/include/flang/Optimizer/Builder/Runtime/Numeric.h b/flang/include/flang/Optimizer/Builder/Runtime/Numeric.h
index 552df43ab85d..c1a72478e224 100644
--- a/flang/include/flang/Optimizer/Builder/Runtime/Numeric.h
+++ b/flang/include/flang/Optimizer/Builder/Runtime/Numeric.h
@@ -26,6 +26,10 @@ mlir::Value genExponent(fir::FirOpBuilder &builder, mlir::Location loc,
mlir::Value genFraction(fir::FirOpBuilder &builder, mlir::Location loc,
mlir::Value x);
+/// Generate call to Mod intrinsic runtime routine.
+mlir::Value genMod(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/Lower/IntrinsicCall.cpp b/flang/lib/Lower/IntrinsicCall.cpp
index 5eb527f0cc24..2294780910bd 100644
--- a/flang/lib/Lower/IntrinsicCall.cpp
+++ b/flang/lib/Lower/IntrinsicCall.cpp
@@ -3393,11 +3393,9 @@ mlir::Value IntrinsicLibrary::genMod(mlir::Type resultType,
if (resultType.isa<mlir::IntegerType>())
return builder.create<mlir::arith::RemSIOp>(loc, args[0], args[1]);
- // Use runtime. Note that mlir::arith::RemFOp implements floating point
- // remainder, but it does not work with fir::Real type.
- // TODO: consider using mlir::arith::RemFOp when possible, that may help
- // folding and optimizations.
- return genRuntimeCall("mod", resultType, args);
+ // Use runtime.
+ return builder.createConvert(
+ loc, resultType, fir::runtime::genMod(builder, loc, args[0], args[1]));
}
// MODULO
diff --git a/flang/lib/Optimizer/Builder/Runtime/Numeric.cpp b/flang/lib/Optimizer/Builder/Runtime/Numeric.cpp
index 2f77c3bc4a03..cb4035d53d5b 100644
--- a/flang/lib/Optimizer/Builder/Runtime/Numeric.cpp
+++ b/flang/lib/Optimizer/Builder/Runtime/Numeric.cpp
@@ -90,6 +90,34 @@ struct ForcedFraction16 {
}
};
+/// Placeholder for real*10 version of Mod Intrinsic
+struct ForcedMod10 {
+ static constexpr const char *name = ExpandAndQuoteKey(RTNAME(ModReal10));
+ static constexpr fir::runtime::FuncTypeBuilderFunc getTypeModel() {
+ return [](mlir::MLIRContext *ctx) {
+ auto fltTy = mlir::FloatType::getF80(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*16 version of Mod Intrinsic
+struct ForcedMod16 {
+ static constexpr const char *name = ExpandAndQuoteKey(RTNAME(ModReal16));
+ 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));
@@ -270,6 +298,38 @@ mlir::Value fir::runtime::genFraction(fir::FirOpBuilder &builder,
return builder.create<fir::CallOp>(loc, func, args).getResult(0);
}
+/// Generate call to Mod intrinsic runtime routine.
+mlir::Value fir::runtime::genMod(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");
+
+ if (fltTy.isF16())
+ TODO(loc, "support for REAL with KIND = 2 in MOD");
+ else if (fltTy.isF32())
+ func = fir::runtime::getRuntimeFunc<mkRTKey(ModReal4)>(loc, builder);
+ else if (fltTy.isF64())
+ func = fir::runtime::getRuntimeFunc<mkRTKey(ModReal8)>(loc, builder);
+ else if (fltTy.isF80())
+ func = fir::runtime::getRuntimeFunc<ForcedMod10>(loc, builder);
+ else if (fltTy.isF128())
+ func = fir::runtime::getRuntimeFunc<ForcedMod16>(loc, builder);
+ else
+ fir::emitFatalError(loc, "unsupported REAL kind in MOD");
+
+ 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<fir::CallOp>(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/mod.f90 b/flang/test/Lower/Intrinsics/mod.f90
new file mode 100644
index 000000000000..117d78cc96ca
--- /dev/null
+++ b/flang/test/Lower/Intrinsics/mod.f90
@@ -0,0 +1,54 @@
+! RUN: bbc -emit-fir %s -o - | FileCheck %s
+! RUN: %flang_fc1 -emit-fir %s -o - | FileCheck %s
+
+! CHECK-LABEL: func @_QPmod_testr4(
+! CHECK-SAME: %[[arg0:.*]]: !fir.ref<f32>{{.*}}, %[[arg1:.*]]: !fir.ref<f32>{{.*}}, %[[arg2:.*]]: !fir.ref<f32>{{.*}}) {
+subroutine mod_testr4(r, a, p)
+ real(4) :: r, a, p
+! CHECK: %[[V1:.*]] = fir.load %[[arg1]] : !fir.ref<f32>
+! CHECK: %[[V2:.*]] = fir.load %[[arg2]] : !fir.ref<f32>
+! CHECK: %[[FILE:.*]] = fir.address_of(@{{.*}}) : !fir.ref<!fir.char<1,{{.*}}>>
+! CHECK: %[[LINE:.*]] = arith.constant {{[0-9]*}} : i32
+! CHECK: %[[FILEARG:.*]] = fir.convert %[[FILE]] : (!fir.ref<!fir.char<1,{{.*}}>>) -> !fir.ref<i8>
+! CHECK: fir.call @_FortranAModReal4(%[[V1]], %[[V2]], %[[FILEARG]], %[[LINE]]) : (f32, f32, !fir.ref<i8>, i32) -> f32
+ r = mod(a, p)
+end subroutine
+
+! CHECK-LABEL: func @_QPmod_testr8(
+! CHECK-SAME: %[[arg0:.*]]: !fir.ref<f64>{{.*}}, %[[arg1:.*]]: !fir.ref<f64>{{.*}}, %[[arg2:.*]]: !fir.ref<f64>{{.*}}) {
+subroutine mod_testr8(r, a, p)
+ real(8) :: r, a, p
+! CHECK: %[[V1:.*]] = fir.load %[[arg1]] : !fir.ref<f64>
+! CHECK: %[[V2:.*]] = fir.load %[[arg2]] : !fir.ref<f64>
+! CHECK: %[[FILE:.*]] = fir.address_of(@{{.*}}) : !fir.ref<!fir.char<1,{{.*}}>>
+! CHECK: %[[LINE:.*]] = arith.constant {{[0-9]*}} : i32
+! CHECK: %[[FILEARG:.*]] = fir.convert %[[FILE]] : (!fir.ref<!fir.char<1,{{.*}}>>) -> !fir.ref<i8>
+! CHECK: fir.call @_FortranAModReal8(%[[V1]], %[[V2]], %[[FILEARG]], %[[LINE]]) : (f64, f64, !fir.ref<i8>, i32) -> f64
+ r = mod(a, p)
+end subroutine
+
+! CHECK-LABEL: func @_QPmod_testr10(
+! CHECK-SAME: %[[arg0:.*]]: !fir.ref<f80>{{.*}}, %[[arg1:.*]]: !fir.ref<f80>{{.*}}, %[[arg2:.*]]: !fir.ref<f80>{{.*}}) {
+subroutine mod_testr10(r, a, p)
+ real(10) :: r, a, p
+! CHECK: %[[V1:.*]] = fir.load %[[arg1]] : !fir.ref<f80>
+! CHECK: %[[V2:.*]] = fir.load %[[arg2]] : !fir.ref<f80>
+! CHECK: %[[FILE:.*]] = fir.address_of(@{{.*}}) : !fir.ref<!fir.char<1,{{.*}}>>
+! CHECK: %[[LINE:.*]] = arith.constant {{[0-9]*}} : i32
+! CHECK: %[[FILEARG:.*]] = fir.convert %[[FILE]] : (!fir.ref<!fir.char<1,{{.*}}>>) -> !fir.ref<i8>
+! CHECK: fir.call @_FortranAModReal10(%[[V1]], %[[V2]], %[[FILEARG]], %[[LINE]]) : (f80, f80, !fir.ref<i8>, i32) -> f80
+ r = mod(a, p)
+end subroutine
+
+! CHECK-LABEL: func @_QPmod_testr16(
+! CHECK-SAME: %[[arg0:.*]]: !fir.ref<f128>{{.*}}, %[[arg1:.*]]: !fir.ref<f128>{{.*}}, %[[arg2:.*]]: !fir.ref<f128>{{.*}}) {
+subroutine mod_testr16(r, a, p)
+ real(16) :: r, a, p
+! CHECK: %[[V1:.*]] = fir.load %[[arg1]] : !fir.ref<f128>
+! CHECK: %[[V2:.*]] = fir.load %[[arg2]] : !fir.ref<f128>
+! CHECK: %[[FILE:.*]] = fir.address_of(@{{.*}}) : !fir.ref<!fir.char<1,{{.*}}>>
+! CHECK: %[[LINE:.*]] = arith.constant {{[0-9]*}} : i32
+! CHECK: %[[FILEARG:.*]] = fir.convert %[[FILE]] : (!fir.ref<!fir.char<1,{{.*}}>>) -> !fir.ref<i8>
+! CHECK: fir.call @_FortranAModReal16(%[[V1]], %[[V2]], %[[FILEARG]], %[[LINE]]) : (f128, f128, !fir.ref<i8>, i32) -> f128
+ r = mod(a, p)
+end subroutine