@@ -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" ;
10099static constexpr char ieee_get_underflow_mode[] = " ieee_get_underflow_mode" ;
101100static constexpr char ieee_real[] = " ieee_real" ;
102101static constexpr char ieee_rem[] = " ieee_rem" ;
103- static constexpr char ieee_rint[] = " ieee_rint" ;
104102static constexpr char ieee_set_underflow_mode[] = " ieee_set_underflow_mode" ;
105103
106104using 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
44734535mlir::Value
44744536IntrinsicLibrary::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
47524845template <bool isFlag>
47534846void IntrinsicLibrary::genIeeeSetFlagOrHaltingMode (
0 commit comments