Skip to content

[flang] Lower REAL(16) MODULO to Float128Math library call. #85322

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Mar 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions flang/include/flang/Optimizer/Builder/Runtime/Numeric.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
7 changes: 7 additions & 0 deletions flang/lib/Optimizer/Builder/IntrinsicCall.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<mlir::arith::RemFOp>(loc, args[0], args[1]);
mlir::Value zero = builder.createRealZeroConstant(loc, remainder.getType());
auto remainderIsNotZero = builder.create<mlir::arith::CmpFOp>(
Expand Down
41 changes: 41 additions & 0 deletions flang/lib/Optimizer/Builder/Runtime/Numeric.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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));
Expand Down Expand Up @@ -323,6 +337,33 @@ mlir::Value fir::runtime::genMod(fir::FirOpBuilder &builder, mlir::Location loc,
return builder.create<fir::CallOp>(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<ForcedModulo16>(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<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,
Expand Down
13 changes: 1 addition & 12 deletions flang/test/Lower/Intrinsics/modulo.f90
Original file line number Diff line number Diff line change
Expand Up @@ -40,17 +40,6 @@ subroutine modulo_testi(r, a, p)
! CHECK-SAME: %[[arg0:.*]]: !fir.ref<f128>{{.*}}, %[[arg1:.*]]: !fir.ref<f128>{{.*}}, %[[arg2:.*]]: !fir.ref<f128>{{.*}}) {
subroutine modulo_testr16(r, a, p)
real(16) :: r, a, p
! CHECK-DAG: %[[a:.*]] = fir.load %[[arg1]] : !fir.ref<f128>
! CHECK-DAG: %[[p:.*]] = fir.load %[[arg2]] : !fir.ref<f128>
! 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<f128>
! CHECK: fir.call @_FortranAModuloReal16({{.*}}){{.*}}: (f128, f128, !fir.ref<i8>, i32) -> f128
r = modulo(a, p)
end subroutine