@@ -97,7 +97,6 @@ static bool isStaticallyPresent(const fir::ExtendedValue &exv) {
9797
9898// / IEEE module procedure names not yet implemented for genModuleProcTODO.
9999static constexpr char ieee_get_underflow_mode[] = " ieee_get_underflow_mode" ;
100- static constexpr char ieee_real[] = " ieee_real" ;
101100static constexpr char ieee_rem[] = " ieee_rem" ;
102101static constexpr char ieee_set_underflow_mode[] = " ieee_set_underflow_mode" ;
103102
@@ -362,7 +361,7 @@ static constexpr IntrinsicHandler handlers[]{
362361 {" ieee_quiet_le" , &I::genIeeeQuietCompare<mlir::arith::CmpFPredicate::OLE>},
363362 {" ieee_quiet_lt" , &I::genIeeeQuietCompare<mlir::arith::CmpFPredicate::OLT>},
364363 {" ieee_quiet_ne" , &I::genIeeeQuietCompare<mlir::arith::CmpFPredicate::UNE>},
365- {" ieee_real" , &I::genModuleProcTODO<ieee_real> },
364+ {" ieee_real" , &I::genIeeeReal },
366365 {" ieee_rem" , &I::genModuleProcTODO<ieee_rem>},
367366 {" ieee_rint" , &I::genIeeeRint},
368367 {" ieee_round_eq" , &I::genIeeeTypeCompare<mlir::arith::CmpIPredicate::eq>},
@@ -4799,6 +4798,238 @@ IntrinsicLibrary::genIeeeQuietCompare(mlir::Type resultType,
47994798 return builder.create <fir::ConvertOp>(loc, resultType, res);
48004799}
48014800
4801+ // IEEE_REAL
4802+ mlir::Value IntrinsicLibrary::genIeeeReal (mlir::Type resultType,
4803+ llvm::ArrayRef<mlir::Value> args) {
4804+ // Convert integer or real argument A to a real of a specified kind.
4805+ // Round according to the current rounding mode.
4806+ // Signal IEEE_INVALID if A is an sNaN, and return a qNaN.
4807+ // Signal IEEE_UNDERFLOW for an inexact subnormal or zero result.
4808+ // Signal IEEE_OVERFLOW if A is finite and the result is infinite.
4809+ // Signal IEEE_INEXACT for an inexact result.
4810+ //
4811+ // if (type(a) == resultType) {
4812+ // // Conversion to the same type is a nop except for sNaN processing.
4813+ // result = a
4814+ // } else {
4815+ // result = r = real(a, kind(result))
4816+ // // Conversion to a larger type is exact.
4817+ // if (c_sizeof(a) >= c_sizeof(r)) {
4818+ // b = (a is integer) ? int(r, kind(a)) : real(r, kind(a))
4819+ // if (a == b || isNaN(a)) {
4820+ // // a is {-0, +0, -inf, +inf, NaN} or exact; result is r
4821+ // } else {
4822+ // // odd(r) is true if the low bit of significand(r) is 1
4823+ // // rounding mode ieee_other is an alias for mode ieee_nearest
4824+ // if (a < b) {
4825+ // if (mode == ieee_nearest && odd(r)) result = ieee_next_down(r)
4826+ // if (mode == ieee_other && odd(r)) result = ieee_next_down(r)
4827+ // if (mode == ieee_to_zero && a > 0) result = ieee_next_down(r)
4828+ // if (mode == ieee_away && a < 0) result = ieee_next_down(r)
4829+ // if (mode == ieee_down) result = ieee_next_down(r)
4830+ // } else { // a > b
4831+ // if (mode == ieee_nearest && odd(r)) result = ieee_next_up(r)
4832+ // if (mode == ieee_other && odd(r)) result = ieee_next_up(r)
4833+ // if (mode == ieee_to_zero && a < 0) result = ieee_next_up(r)
4834+ // if (mode == ieee_away && a > 0) result = ieee_next_up(r)
4835+ // if (mode == ieee_up) result = ieee_next_up(r)
4836+ // }
4837+ // }
4838+ // }
4839+ // }
4840+
4841+ assert (args.size () == 2 );
4842+ mlir::Type i1Ty = builder.getI1Type ();
4843+ mlir::Type f32Ty = mlir::FloatType::getF32 (builder.getContext ());
4844+ mlir::Value a = args[0 ];
4845+ mlir::Type aType = a.getType ();
4846+
4847+ // If the argument is an sNaN, raise an invalid exception and return a qNaN.
4848+ // Otherwise return the argument.
4849+ auto processSnan = [&](mlir::Value x) {
4850+ fir::IfOp ifOp = builder.create <fir::IfOp>(loc, resultType,
4851+ genIsFPClass (i1Ty, x, snanTest),
4852+ /* withElseRegion=*/ true );
4853+ builder.setInsertionPointToStart (&ifOp.getThenRegion ().front ());
4854+ genRaiseExcept (_FORTRAN_RUNTIME_IEEE_INVALID);
4855+ builder.create <fir::ResultOp>(loc, genQNan (resultType));
4856+ builder.setInsertionPointToStart (&ifOp.getElseRegion ().front ());
4857+ builder.create <fir::ResultOp>(loc, x);
4858+ builder.setInsertionPointAfter (ifOp);
4859+ return ifOp.getResult (0 );
4860+ };
4861+
4862+ // Conversion is a nop, except that A may be an sNaN.
4863+ if (resultType == aType)
4864+ return processSnan (a);
4865+
4866+ // Can't directly convert between kind=2 and kind=3.
4867+ mlir::Value r, r1;
4868+ if ((aType.isBF16 () && resultType.isF16 ()) ||
4869+ (aType.isF16 () && resultType.isBF16 ())) {
4870+ a = builder.createConvert (loc, f32Ty, a);
4871+ aType = f32Ty;
4872+ }
4873+ r = builder.create <fir::ConvertOp>(loc, resultType, a);
4874+
4875+ mlir::IntegerType aIntType = mlir::dyn_cast<mlir::IntegerType>(aType);
4876+ mlir::FloatType aFloatType = mlir::dyn_cast<mlir::FloatType>(aType);
4877+ mlir::FloatType resultFloatType = mlir::dyn_cast<mlir::FloatType>(resultType);
4878+
4879+ // Conversion from a smaller type to a larger type is exact.
4880+ if ((aIntType ? aIntType.getWidth () : aFloatType.getWidth ()) <
4881+ resultFloatType.getWidth ())
4882+ return aIntType ? r : processSnan (r);
4883+
4884+ // A possibly inexact conversion result may need to be rounded up or down.
4885+ mlir::Value b = builder.create <fir::ConvertOp>(loc, aType, r);
4886+ mlir::Value aEqB;
4887+ if (aIntType)
4888+ aEqB = builder.create <mlir::arith::CmpIOp>(
4889+ loc, mlir::arith::CmpIPredicate::eq, a, b);
4890+ else
4891+ aEqB = builder.create <mlir::arith::CmpFOp>(
4892+ loc, mlir::arith::CmpFPredicate::UEQ, a, b);
4893+
4894+ // [a == b] a is a NaN or r is exact (a may be -0, +0, -inf, +inf) -- return r
4895+ fir::IfOp ifOp1 = builder.create <fir::IfOp>(loc, resultType, aEqB,
4896+ /* withElseRegion=*/ true );
4897+ builder.setInsertionPointToStart (&ifOp1.getThenRegion ().front ());
4898+ builder.create <fir::ResultOp>(loc, aIntType ? r : processSnan (r));
4899+
4900+ // Code common to (a < b) and (a > b) branches.
4901+ builder.setInsertionPointToStart (&ifOp1.getElseRegion ().front ());
4902+ mlir::func::FuncOp getRound = fir::factory::getLlvmGetRounding (builder);
4903+ mlir::Value mode = builder.create <fir::CallOp>(loc, getRound).getResult (0 );
4904+ mlir::Value aIsNegative, aIsPositive;
4905+ if (aIntType) {
4906+ mlir::Value zero = builder.createIntegerConstant (loc, aIntType, 0 );
4907+ aIsNegative = builder.create <mlir::arith::CmpIOp>(
4908+ loc, mlir::arith::CmpIPredicate::slt, a, zero);
4909+ aIsPositive = builder.create <mlir::arith::CmpIOp>(
4910+ loc, mlir::arith::CmpIPredicate::sgt, a, zero);
4911+ } else {
4912+ mlir::Value zero = builder.createRealZeroConstant (loc, aFloatType);
4913+ aIsNegative = builder.create <mlir::arith::CmpFOp>(
4914+ loc, mlir::arith::CmpFPredicate::OLT, a, zero);
4915+ aIsPositive = builder.create <mlir::arith::CmpFOp>(
4916+ loc, mlir::arith::CmpFPredicate::OGT, a, zero);
4917+ }
4918+ mlir::Type resultIntType = builder.getIntegerType (resultFloatType.getWidth ());
4919+ mlir::Value resultCast =
4920+ builder.create <mlir::arith::BitcastOp>(loc, resultIntType, r);
4921+ mlir::Value one = builder.createIntegerConstant (loc, resultIntType, 1 );
4922+ mlir::Value rIsOdd = builder.create <fir::ConvertOp>(
4923+ loc, i1Ty, builder.create <mlir::arith::AndIOp>(loc, resultCast, one));
4924+ // Check for a rounding mode match.
4925+ auto match = [&](int m) {
4926+ return builder.create <mlir::arith::CmpIOp>(
4927+ loc, mlir::arith::CmpIPredicate::eq, mode,
4928+ builder.createIntegerConstant (loc, mode.getType (), m));
4929+ };
4930+ mlir::Value roundToNearestBit = builder.create <mlir::arith::OrIOp>(
4931+ loc,
4932+ // IEEE_OTHER is an alias for IEEE_NEAREST.
4933+ match (_FORTRAN_RUNTIME_IEEE_NEAREST), match (_FORTRAN_RUNTIME_IEEE_OTHER));
4934+ mlir::Value roundToNearest =
4935+ builder.create <mlir::arith::AndIOp>(loc, roundToNearestBit, rIsOdd);
4936+ mlir::Value roundToZeroBit = match (_FORTRAN_RUNTIME_IEEE_TO_ZERO);
4937+ mlir::Value roundAwayBit = match (_FORTRAN_RUNTIME_IEEE_AWAY);
4938+ mlir::Value roundToZero, roundAway, mustAdjust;
4939+ fir::IfOp adjustIfOp;
4940+ mlir::Value aLtB;
4941+ if (aIntType)
4942+ aLtB = builder.create <mlir::arith::CmpIOp>(
4943+ loc, mlir::arith::CmpIPredicate::slt, a, b);
4944+ else
4945+ aLtB = builder.create <mlir::arith::CmpFOp>(
4946+ loc, mlir::arith::CmpFPredicate::OLT, a, b);
4947+ mlir::Value upResult =
4948+ builder.create <mlir::arith::AddIOp>(loc, resultCast, one);
4949+ mlir::Value downResult =
4950+ builder.create <mlir::arith::SubIOp>(loc, resultCast, one);
4951+
4952+ // (a < b): r is inexact -- return r or ieee_next_down(r)
4953+ fir::IfOp ifOp2 = builder.create <fir::IfOp>(loc, resultType, aLtB,
4954+ /* withElseRegion=*/ true );
4955+ builder.setInsertionPointToStart (&ifOp2.getThenRegion ().front ());
4956+ roundToZero =
4957+ builder.create <mlir::arith::AndIOp>(loc, roundToZeroBit, aIsPositive);
4958+ roundAway =
4959+ builder.create <mlir::arith::AndIOp>(loc, roundAwayBit, aIsNegative);
4960+ mlir::Value roundDown = match (_FORTRAN_RUNTIME_IEEE_DOWN);
4961+ mustAdjust =
4962+ builder.create <mlir::arith::OrIOp>(loc, roundToNearest, roundToZero);
4963+ mustAdjust = builder.create <mlir::arith::OrIOp>(loc, mustAdjust, roundAway);
4964+ mustAdjust = builder.create <mlir::arith::OrIOp>(loc, mustAdjust, roundDown);
4965+ adjustIfOp = builder.create <fir::IfOp>(loc, resultType, mustAdjust,
4966+ /* withElseRegion=*/ true );
4967+ builder.setInsertionPointToStart (&adjustIfOp.getThenRegion ().front ());
4968+ if (resultType.isF80 ())
4969+ r1 = fir::runtime::genNearest (builder, loc, r,
4970+ builder.createBool (loc, false ));
4971+ else
4972+ r1 = builder.create <mlir::arith::BitcastOp>(
4973+ loc, resultType,
4974+ builder.create <mlir::arith::SelectOp>(loc, aIsNegative, upResult,
4975+ downResult));
4976+ builder.create <fir::ResultOp>(loc, r1);
4977+ builder.setInsertionPointToStart (&adjustIfOp.getElseRegion ().front ());
4978+ builder.create <fir::ResultOp>(loc, r);
4979+ builder.setInsertionPointAfter (adjustIfOp);
4980+ builder.create <fir::ResultOp>(loc, adjustIfOp.getResult (0 ));
4981+
4982+ // (a > b): r is inexact -- return r or ieee_next_up(r)
4983+ builder.setInsertionPointToStart (&ifOp2.getElseRegion ().front ());
4984+ roundToZero =
4985+ builder.create <mlir::arith::AndIOp>(loc, roundToZeroBit, aIsNegative);
4986+ roundAway =
4987+ builder.create <mlir::arith::AndIOp>(loc, roundAwayBit, aIsPositive);
4988+ mlir::Value roundUp = match (_FORTRAN_RUNTIME_IEEE_UP);
4989+ mustAdjust =
4990+ builder.create <mlir::arith::OrIOp>(loc, roundToNearest, roundToZero);
4991+ mustAdjust = builder.create <mlir::arith::OrIOp>(loc, mustAdjust, roundAway);
4992+ mustAdjust = builder.create <mlir::arith::OrIOp>(loc, mustAdjust, roundUp);
4993+ adjustIfOp = builder.create <fir::IfOp>(loc, resultType, mustAdjust,
4994+ /* withElseRegion=*/ true );
4995+ builder.setInsertionPointToStart (&adjustIfOp.getThenRegion ().front ());
4996+ if (resultType.isF80 ())
4997+ r1 = fir::runtime::genNearest (builder, loc, r,
4998+ builder.createBool (loc, true ));
4999+ else
5000+ r1 = builder.create <mlir::arith::BitcastOp>(
5001+ loc, resultType,
5002+ builder.create <mlir::arith::SelectOp>(loc, aIsPositive, upResult,
5003+ downResult));
5004+ builder.create <fir::ResultOp>(loc, r1);
5005+ builder.setInsertionPointToStart (&adjustIfOp.getElseRegion ().front ());
5006+ builder.create <fir::ResultOp>(loc, r);
5007+ builder.setInsertionPointAfter (adjustIfOp);
5008+ builder.create <fir::ResultOp>(loc, adjustIfOp.getResult (0 ));
5009+
5010+ // Generate exceptions for (a < b) and (a > b) branches.
5011+ builder.setInsertionPointAfter (ifOp2);
5012+ r = ifOp2.getResult (0 );
5013+ fir::IfOp exceptIfOp1 = builder.create <fir::IfOp>(
5014+ loc, genIsFPClass (i1Ty, r, infiniteTest), /* withElseRegion=*/ true );
5015+ builder.setInsertionPointToStart (&exceptIfOp1.getThenRegion ().front ());
5016+ genRaiseExcept (_FORTRAN_RUNTIME_IEEE_OVERFLOW |
5017+ _FORTRAN_RUNTIME_IEEE_INEXACT);
5018+ builder.setInsertionPointToStart (&exceptIfOp1.getElseRegion ().front ());
5019+ fir::IfOp exceptIfOp2 = builder.create <fir::IfOp>(
5020+ loc, genIsFPClass (i1Ty, r, subnormalTest | zeroTest),
5021+ /* withElseRegion=*/ true );
5022+ builder.setInsertionPointToStart (&exceptIfOp2.getThenRegion ().front ());
5023+ genRaiseExcept (_FORTRAN_RUNTIME_IEEE_UNDERFLOW |
5024+ _FORTRAN_RUNTIME_IEEE_INEXACT);
5025+ builder.setInsertionPointToStart (&exceptIfOp2.getElseRegion ().front ());
5026+ genRaiseExcept (_FORTRAN_RUNTIME_IEEE_INEXACT);
5027+ builder.setInsertionPointAfter (exceptIfOp1);
5028+ builder.create <fir::ResultOp>(loc, ifOp2.getResult (0 ));
5029+ builder.setInsertionPointAfter (ifOp1);
5030+ return ifOp1.getResult (0 );
5031+ }
5032+
48025033// IEEE_RINT
48035034mlir::Value IntrinsicLibrary::genIeeeRint (mlir::Type resultType,
48045035 llvm::ArrayRef<mlir::Value> args) {
0 commit comments