@@ -97,7 +97,6 @@ static bool isStaticallyPresent(const fir::ExtendedValue &exv) {
97
97
98
98
// / IEEE module procedure names not yet implemented for genModuleProcTODO.
99
99
static constexpr char ieee_get_underflow_mode[] = " ieee_get_underflow_mode" ;
100
- static constexpr char ieee_real[] = " ieee_real" ;
101
100
static constexpr char ieee_rem[] = " ieee_rem" ;
102
101
static constexpr char ieee_set_underflow_mode[] = " ieee_set_underflow_mode" ;
103
102
@@ -362,7 +361,7 @@ static constexpr IntrinsicHandler handlers[]{
362
361
{" ieee_quiet_le" , &I::genIeeeQuietCompare<mlir::arith::CmpFPredicate::OLE>},
363
362
{" ieee_quiet_lt" , &I::genIeeeQuietCompare<mlir::arith::CmpFPredicate::OLT>},
364
363
{" ieee_quiet_ne" , &I::genIeeeQuietCompare<mlir::arith::CmpFPredicate::UNE>},
365
- {" ieee_real" , &I::genModuleProcTODO<ieee_real> },
364
+ {" ieee_real" , &I::genIeeeReal },
366
365
{" ieee_rem" , &I::genModuleProcTODO<ieee_rem>},
367
366
{" ieee_rint" , &I::genIeeeRint},
368
367
{" ieee_round_eq" , &I::genIeeeTypeCompare<mlir::arith::CmpIPredicate::eq>},
@@ -4799,6 +4798,238 @@ IntrinsicLibrary::genIeeeQuietCompare(mlir::Type resultType,
4799
4798
return builder.create <fir::ConvertOp>(loc, resultType, res);
4800
4799
}
4801
4800
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
+
4802
5033
// IEEE_RINT
4803
5034
mlir::Value IntrinsicLibrary::genIeeeRint (mlir::Type resultType,
4804
5035
llvm::ArrayRef<mlir::Value> args) {
0 commit comments