@@ -96,11 +96,9 @@ static bool isStaticallyPresent(const fir::ExtendedValue &exv) {
96
96
}
97
97
98
98
// / IEEE module procedure names not yet implemented for genModuleProcTODO.
99
- static constexpr char ieee_int[] = " ieee_int" ;
100
99
static constexpr char ieee_get_underflow_mode[] = " ieee_get_underflow_mode" ;
101
100
static constexpr char ieee_real[] = " ieee_real" ;
102
101
static constexpr char ieee_rem[] = " ieee_rem" ;
103
- static constexpr char ieee_rint[] = " ieee_rint" ;
104
102
static constexpr char ieee_set_underflow_mode[] = " ieee_set_underflow_mode" ;
105
103
106
104
using I = IntrinsicLibrary;
@@ -331,7 +329,7 @@ static constexpr IntrinsicHandler handlers[]{
331
329
/* isElemental=*/ false },
332
330
{" ieee_get_status" , &I::genIeeeGetOrSetStatus</* isGet=*/ true >},
333
331
{" ieee_get_underflow_mode" , &I::genModuleProcTODO<ieee_get_underflow_mode>},
334
- {" ieee_int" , &I::genModuleProcTODO<ieee_int> },
332
+ {" ieee_int" , &I::genIeeeInt },
335
333
{" ieee_is_finite" , &I::genIeeeIsFinite},
336
334
{" ieee_is_nan" , &I::genIeeeIsNan},
337
335
{" ieee_is_negative" , &I::genIeeeIsNegative},
@@ -364,7 +362,7 @@ static constexpr IntrinsicHandler handlers[]{
364
362
{" ieee_quiet_ne" , &I::genIeeeQuietCompare<mlir::arith::CmpFPredicate::UNE>},
365
363
{" ieee_real" , &I::genModuleProcTODO<ieee_real>},
366
364
{" ieee_rem" , &I::genModuleProcTODO<ieee_rem>},
367
- {" ieee_rint" , &I::genModuleProcTODO<ieee_rint> },
365
+ {" ieee_rint" , &I::genIeeeRint },
368
366
{" ieee_round_eq" , &I::genIeeeTypeCompare<mlir::arith::CmpIPredicate::eq>},
369
367
{" ieee_round_ne" , &I::genIeeeTypeCompare<mlir::arith::CmpIPredicate::ne>},
370
368
{" ieee_set_flag" , &I::genIeeeSetFlagOrHaltingMode</* isFlag=*/ true >},
@@ -1240,6 +1238,14 @@ static constexpr MathOperation mathOperations[] = {
1240
1238
{" log_gamma" , " lgamma" , genFuncType<Ty::Real<8 >, Ty::Real<8 >>, genLibCall},
1241
1239
{" log_gamma" , RTNAME_STRING (LgammaF128), FuncTypeReal16Real16,
1242
1240
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},
1243
1249
// llvm.lround behaves the same way as libm's lround.
1244
1250
{" nint" , " llvm.lround.i64.f64" , genFuncType<Ty::Integer<8 >, Ty::Real<8 >>,
1245
1251
genLibCall},
@@ -4469,6 +4475,62 @@ void IntrinsicLibrary::genIeeeGetOrSetStatus(
4469
4475
genRuntimeCall (isGet ? " fegetenv" : " fesetenv" , i32Ty, addr);
4470
4476
}
4471
4477
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
+
4472
4534
// IEEE_IS_FINITE
4473
4535
mlir::Value
4474
4536
IntrinsicLibrary::genIeeeIsFinite (mlir::Type resultType,
@@ -4748,6 +4810,37 @@ IntrinsicLibrary::genIeeeQuietCompare(mlir::Type resultType,
4748
4810
return builder.create <fir::ConvertOp>(loc, resultType, res);
4749
4811
}
4750
4812
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
+
4751
4844
// IEEE_SET_FLAG, IEEE_SET_HALTING_MODE
4752
4845
template <bool isFlag>
4753
4846
void IntrinsicLibrary::genIeeeSetFlagOrHaltingMode (
0 commit comments