forked from OSchip/llvm-project
[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
This commit is contained in:
parent
75c64c7c4e
commit
1b9faafe91
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
Loading…
Reference in New Issue