Skip to content

Commit 936142e

Browse files
authored
[flang] IEEE_RINT, IEEE_INT (#110509)
IEEE_RINT rounds a real value to an integer-valued real. IEEE_INT rounds a real value to an integer value. The primary IEEE_INT result is generated with a call to IEEE_RINT.
1 parent fe61dbf commit 936142e

File tree

6 files changed

+372
-4
lines changed

6 files changed

+372
-4
lines changed

flang/include/flang/Optimizer/Builder/IntrinsicCall.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -274,6 +274,7 @@ struct IntrinsicLibrary {
274274
template <bool isGet>
275275
void genIeeeGetOrSetStatus(llvm::ArrayRef<fir::ExtendedValue>);
276276
void genIeeeGetRoundingMode(llvm::ArrayRef<fir::ExtendedValue>);
277+
mlir::Value genIeeeInt(mlir::Type, llvm::ArrayRef<mlir::Value>);
277278
mlir::Value genIeeeIsFinite(mlir::Type, llvm::ArrayRef<mlir::Value>);
278279
mlir::Value genIeeeIsNan(mlir::Type, llvm::ArrayRef<mlir::Value>);
279280
mlir::Value genIeeeIsNegative(mlir::Type, llvm::ArrayRef<mlir::Value>);
@@ -284,6 +285,7 @@ struct IntrinsicLibrary {
284285
template <mlir::arith::CmpFPredicate pred>
285286
mlir::Value genIeeeQuietCompare(mlir::Type resultType,
286287
llvm::ArrayRef<mlir::Value>);
288+
mlir::Value genIeeeRint(mlir::Type, llvm::ArrayRef<mlir::Value>);
287289
template <bool isFlag>
288290
void genIeeeSetFlagOrHaltingMode(llvm::ArrayRef<fir::ExtendedValue>);
289291
void genIeeeSetRoundingMode(llvm::ArrayRef<fir::ExtendedValue>);

flang/lib/Optimizer/Builder/IntrinsicCall.cpp

Lines changed: 97 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -96,11 +96,9 @@ static bool isStaticallyPresent(const fir::ExtendedValue &exv) {
9696
}
9797

9898
/// IEEE module procedure names not yet implemented for genModuleProcTODO.
99-
static constexpr char ieee_int[] = "ieee_int";
10099
static constexpr char ieee_get_underflow_mode[] = "ieee_get_underflow_mode";
101100
static constexpr char ieee_real[] = "ieee_real";
102101
static constexpr char ieee_rem[] = "ieee_rem";
103-
static constexpr char ieee_rint[] = "ieee_rint";
104102
static constexpr char ieee_set_underflow_mode[] = "ieee_set_underflow_mode";
105103

106104
using I = IntrinsicLibrary;
@@ -331,7 +329,7 @@ static constexpr IntrinsicHandler handlers[]{
331329
/*isElemental=*/false},
332330
{"ieee_get_status", &I::genIeeeGetOrSetStatus</*isGet=*/true>},
333331
{"ieee_get_underflow_mode", &I::genModuleProcTODO<ieee_get_underflow_mode>},
334-
{"ieee_int", &I::genModuleProcTODO<ieee_int>},
332+
{"ieee_int", &I::genIeeeInt},
335333
{"ieee_is_finite", &I::genIeeeIsFinite},
336334
{"ieee_is_nan", &I::genIeeeIsNan},
337335
{"ieee_is_negative", &I::genIeeeIsNegative},
@@ -364,7 +362,7 @@ static constexpr IntrinsicHandler handlers[]{
364362
{"ieee_quiet_ne", &I::genIeeeQuietCompare<mlir::arith::CmpFPredicate::UNE>},
365363
{"ieee_real", &I::genModuleProcTODO<ieee_real>},
366364
{"ieee_rem", &I::genModuleProcTODO<ieee_rem>},
367-
{"ieee_rint", &I::genModuleProcTODO<ieee_rint>},
365+
{"ieee_rint", &I::genIeeeRint},
368366
{"ieee_round_eq", &I::genIeeeTypeCompare<mlir::arith::CmpIPredicate::eq>},
369367
{"ieee_round_ne", &I::genIeeeTypeCompare<mlir::arith::CmpIPredicate::ne>},
370368
{"ieee_set_flag", &I::genIeeeSetFlagOrHaltingMode</*isFlag=*/true>},
@@ -1240,6 +1238,14 @@ static constexpr MathOperation mathOperations[] = {
12401238
{"log_gamma", "lgamma", genFuncType<Ty::Real<8>, Ty::Real<8>>, genLibCall},
12411239
{"log_gamma", RTNAME_STRING(LgammaF128), FuncTypeReal16Real16,
12421240
genLibF128Call},
1241+
{"nearbyint", "llvm.nearbyint.f32", genFuncType<Ty::Real<4>, Ty::Real<4>>,
1242+
genLibCall},
1243+
{"nearbyint", "llvm.nearbyint.f64", genFuncType<Ty::Real<8>, Ty::Real<8>>,
1244+
genLibCall},
1245+
{"nearbyint", "llvm.nearbyint.f80", genFuncType<Ty::Real<10>, Ty::Real<10>>,
1246+
genLibCall},
1247+
{"nearbyint", RTNAME_STRING(NearbyintF128), FuncTypeReal16Real16,
1248+
genLibF128Call},
12431249
// llvm.lround behaves the same way as libm's lround.
12441250
{"nint", "llvm.lround.i64.f64", genFuncType<Ty::Integer<8>, Ty::Real<8>>,
12451251
genLibCall},
@@ -4469,6 +4475,62 @@ void IntrinsicLibrary::genIeeeGetOrSetStatus(
44694475
genRuntimeCall(isGet ? "fegetenv" : "fesetenv", i32Ty, addr);
44704476
}
44714477

4478+
// IEEE_INT
4479+
mlir::Value IntrinsicLibrary::genIeeeInt(mlir::Type resultType,
4480+
llvm::ArrayRef<mlir::Value> args) {
4481+
// Convert real argument A to an integer, with rounding according to argument
4482+
// ROUND. Signal IEEE_INVALID if A is a NaN, an infinity, or out of range,
4483+
// and return either the largest or smallest integer result value (*).
4484+
// For valid results (when IEEE_INVALID is not signaled), signal IEEE_INEXACT
4485+
// if A is not an exact integral value (*). The (*) choices are processor
4486+
// dependent implementation choices not mandated by the standard.
4487+
// The primary result is generated with a call to IEEE_RINT.
4488+
assert(args.size() == 3);
4489+
mlir::FloatType realType = mlir::cast<mlir::FloatType>(args[0].getType());
4490+
mlir::Value realResult = genIeeeRint(realType, {args[0], args[1]});
4491+
int intWidth = mlir::cast<mlir::IntegerType>(resultType).getWidth();
4492+
mlir::Value intLBound = builder.create<mlir::arith::ConstantOp>(
4493+
loc, resultType,
4494+
builder.getIntegerAttr(resultType,
4495+
llvm::APInt::getBitsSet(intWidth,
4496+
/*lo=*/intWidth - 1,
4497+
/*hi=*/intWidth)));
4498+
mlir::Value intUBound = builder.create<mlir::arith::ConstantOp>(
4499+
loc, resultType,
4500+
builder.getIntegerAttr(resultType,
4501+
llvm::APInt::getBitsSet(intWidth, /*lo=*/0,
4502+
/*hi=*/intWidth - 1)));
4503+
mlir::Value realLBound =
4504+
builder.create<fir::ConvertOp>(loc, realType, intLBound);
4505+
mlir::Value realUBound = builder.create<mlir::arith::NegFOp>(loc, realLBound);
4506+
mlir::Value aGreaterThanLBound = builder.create<mlir::arith::CmpFOp>(
4507+
loc, mlir::arith::CmpFPredicate::OGE, realResult, realLBound);
4508+
mlir::Value aLessThanUBound = builder.create<mlir::arith::CmpFOp>(
4509+
loc, mlir::arith::CmpFPredicate::OLT, realResult, realUBound);
4510+
mlir::Value resultIsValid = builder.create<mlir::arith::AndIOp>(
4511+
loc, aGreaterThanLBound, aLessThanUBound);
4512+
4513+
// Result is valid. It may be exact or inexact.
4514+
mlir::Value result;
4515+
fir::IfOp ifOp = builder.create<fir::IfOp>(loc, resultType, resultIsValid,
4516+
/*withElseRegion=*/true);
4517+
builder.setInsertionPointToStart(&ifOp.getThenRegion().front());
4518+
mlir::Value inexact = builder.create<mlir::arith::CmpFOp>(
4519+
loc, mlir::arith::CmpFPredicate::ONE, args[0], realResult);
4520+
genRaiseExcept(_FORTRAN_RUNTIME_IEEE_INEXACT, inexact);
4521+
result = builder.create<fir::ConvertOp>(loc, resultType, realResult);
4522+
builder.create<fir::ResultOp>(loc, result);
4523+
4524+
// Result is invalid.
4525+
builder.setInsertionPointToStart(&ifOp.getElseRegion().front());
4526+
genRaiseExcept(_FORTRAN_RUNTIME_IEEE_INVALID);
4527+
result = builder.create<mlir::arith::SelectOp>(loc, aGreaterThanLBound,
4528+
intUBound, intLBound);
4529+
builder.create<fir::ResultOp>(loc, result);
4530+
builder.setInsertionPointAfter(ifOp);
4531+
return ifOp.getResult(0);
4532+
}
4533+
44724534
// IEEE_IS_FINITE
44734535
mlir::Value
44744536
IntrinsicLibrary::genIeeeIsFinite(mlir::Type resultType,
@@ -4748,6 +4810,37 @@ IntrinsicLibrary::genIeeeQuietCompare(mlir::Type resultType,
47484810
return builder.create<fir::ConvertOp>(loc, resultType, res);
47494811
}
47504812

4813+
// IEEE_RINT
4814+
mlir::Value IntrinsicLibrary::genIeeeRint(mlir::Type resultType,
4815+
llvm::ArrayRef<mlir::Value> args) {
4816+
// Return the value of real argument A rounded to an integer value according
4817+
// to argument ROUND if present, otherwise according to the current rounding
4818+
// mode. If ROUND is not present, signal IEEE_INEXACT if A is not an exact
4819+
// integral value.
4820+
assert(args.size() == 2);
4821+
mlir::Value a = args[0];
4822+
mlir::func::FuncOp getRound = fir::factory::getLlvmGetRounding(builder);
4823+
mlir::func::FuncOp setRound = fir::factory::getLlvmSetRounding(builder);
4824+
mlir::Value mode;
4825+
if (isStaticallyPresent(args[1])) {
4826+
mode = builder.create<fir::CallOp>(loc, getRound).getResult(0);
4827+
genIeeeSetRoundingMode({args[1]});
4828+
}
4829+
if (mlir::cast<mlir::FloatType>(resultType).getWidth() == 16)
4830+
a = builder.create<fir::ConvertOp>(
4831+
loc, mlir::FloatType::getF32(builder.getContext()), a);
4832+
mlir::Value result = builder.create<fir::ConvertOp>(
4833+
loc, resultType, genRuntimeCall("nearbyint", a.getType(), a));
4834+
if (isStaticallyPresent(args[1])) {
4835+
builder.create<fir::CallOp>(loc, setRound, mode);
4836+
} else {
4837+
mlir::Value inexact = builder.create<mlir::arith::CmpFOp>(
4838+
loc, mlir::arith::CmpFPredicate::ONE, args[0], result);
4839+
genRaiseExcept(_FORTRAN_RUNTIME_IEEE_INEXACT, inexact);
4840+
}
4841+
return result;
4842+
}
4843+
47514844
// IEEE_SET_FLAG, IEEE_SET_HALTING_MODE
47524845
template <bool isFlag>
47534846
void IntrinsicLibrary::genIeeeSetFlagOrHaltingMode(

flang/runtime/Float128Math/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ set(sources
4747
mod-real.cpp
4848
modulo-real.cpp
4949
nearest.cpp
50+
nearbyint.cpp
5051
norm2.cpp
5152
pow.cpp
5253
random.cpp

flang/runtime/Float128Math/math-entries.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@ DEFINE_FALLBACK_I64(Llround)
9292
DEFINE_FALLBACK_F128(Log)
9393
DEFINE_FALLBACK_F128(Log10)
9494
DEFINE_FALLBACK_I32(Lround)
95+
DEFINE_FALLBACK_F128(Nearbyint)
9596
DEFINE_FALLBACK_F128(Nextafter)
9697
DEFINE_FALLBACK_F128(Pow)
9798
DEFINE_FALLBACK_F128(Qnan)
@@ -140,6 +141,7 @@ DEFINE_SIMPLE_ALIAS(Llround, llroundq)
140141
DEFINE_SIMPLE_ALIAS(Log, logq)
141142
DEFINE_SIMPLE_ALIAS(Log10, log10q)
142143
DEFINE_SIMPLE_ALIAS(Lround, lroundq)
144+
DEFINE_SIMPLE_ALIAS(Nearbyint, nearbyintq)
143145
DEFINE_SIMPLE_ALIAS(Nextafter, nextafterq)
144146
DEFINE_SIMPLE_ALIAS(Pow, powq)
145147
DEFINE_SIMPLE_ALIAS(Round, roundq)
@@ -194,6 +196,7 @@ DEFINE_SIMPLE_ALIAS(Llround, std::llround)
194196
DEFINE_SIMPLE_ALIAS(Log, std::log)
195197
DEFINE_SIMPLE_ALIAS(Log10, std::log10)
196198
DEFINE_SIMPLE_ALIAS(Lround, std::lround)
199+
DEFINE_SIMPLE_ALIAS(Nearbyint, std::nearbyint)
197200
DEFINE_SIMPLE_ALIAS(Nextafter, std::nextafter)
198201
DEFINE_SIMPLE_ALIAS(Pow, std::pow)
199202
DEFINE_SIMPLE_ALIAS(Round, std::round)
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
//===-- runtime/Float128Math/nearbyint.cpp --------------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#include "math-entries.h"
10+
11+
namespace Fortran::runtime {
12+
extern "C" {
13+
14+
#if HAS_LDBL128 || HAS_FLOAT128
15+
CppTypeFor<TypeCategory::Real, 16> RTDEF(NearbyintF128)(
16+
CppTypeFor<TypeCategory::Real, 16> x) {
17+
return Nearbyint<true>::invoke(x);
18+
}
19+
#endif
20+
21+
} // extern "C"
22+
} // namespace Fortran::runtime

0 commit comments

Comments
 (0)