@@ -657,10 +657,61 @@ static llvm::cl::opt<bool>
657657 " instead of libm complex operations" ),
658658 llvm::cl::init(false ));
659659
660+ // / Return a string containing the given Fortran intrinsic name
661+ // / with the type of its arguments specified in funcType
662+ // / surrounded by the given prefix/suffix.
663+ static std::string
664+ prettyPrintIntrinsicName (fir::FirOpBuilder &builder, mlir::Location loc,
665+ llvm::StringRef prefix, llvm::StringRef name,
666+ llvm::StringRef suffix, mlir::FunctionType funcType) {
667+ std::string output = prefix.str ();
668+ llvm::raw_string_ostream sstream (output);
669+ if (name == " pow" ) {
670+ assert (funcType.getNumInputs () == 2 && " power operator has two arguments" );
671+ std::string displayName{" ** " };
672+ sstream << numericMlirTypeToFortran (builder, funcType.getInput (0 ), loc,
673+ displayName)
674+ << displayName
675+ << numericMlirTypeToFortran (builder, funcType.getInput (1 ), loc,
676+ displayName);
677+ } else {
678+ sstream << name.upper () << " (" ;
679+ if (funcType.getNumInputs () > 0 )
680+ sstream << numericMlirTypeToFortran (builder, funcType.getInput (0 ), loc,
681+ name);
682+ for (mlir::Type argType : funcType.getInputs ().drop_front ()) {
683+ sstream << " , " << numericMlirTypeToFortran (builder, argType, loc, name);
684+ }
685+ sstream << " )" ;
686+ }
687+ sstream << suffix;
688+ return output;
689+ }
690+
691+ // Generate a call to the Fortran runtime library providing
692+ // support for 128-bit float math via a third-party library.
693+ // If the compiler is built without FLANG_RUNTIME_F128_MATH_LIB,
694+ // this function will report an error.
695+ static mlir::Value genLibF128Call (fir::FirOpBuilder &builder,
696+ mlir::Location loc,
697+ const MathOperation &mathOp,
698+ mlir::FunctionType libFuncType,
699+ llvm::ArrayRef<mlir::Value> args) {
700+ #ifndef FLANG_RUNTIME_F128_MATH_LIB
701+ std::string message = prettyPrintIntrinsicName (
702+ builder, loc, " compiler is built without support for '" , mathOp.key , " '" ,
703+ libFuncType);
704+ fir::emitFatalError (loc, message, /* genCrashDiag=*/ false );
705+ #else // FLANG_RUNTIME_F128_MATH_LIB
706+ return genLibCall (builder, loc, mathOp, libFuncType, args);
707+ #endif // FLANG_RUNTIME_F128_MATH_LIB
708+ }
709+
660710mlir::Value genLibCall (fir::FirOpBuilder &builder, mlir::Location loc,
661- llvm::StringRef libFuncName ,
711+ const MathOperation &mathOp ,
662712 mlir::FunctionType libFuncType,
663713 llvm::ArrayRef<mlir::Value> args) {
714+ llvm::StringRef libFuncName = mathOp.runtimeFunc ;
664715 LLVM_DEBUG (llvm::dbgs () << " Generating '" << libFuncName
665716 << " ' call with type " ;
666717 libFuncType.dump (); llvm::dbgs () << " \n " );
@@ -718,7 +769,7 @@ mlir::Value genLibCall(fir::FirOpBuilder &builder, mlir::Location loc,
718769
719770mlir::Value genLibSplitComplexArgsCall (fir::FirOpBuilder &builder,
720771 mlir::Location loc,
721- llvm::StringRef libFuncName ,
772+ const MathOperation &mathOp ,
722773 mlir::FunctionType libFuncType,
723774 llvm::ArrayRef<mlir::Value> args) {
724775 assert (args.size () == 2 && " Incorrect #args to genLibSplitComplexArgsCall" );
@@ -762,13 +813,12 @@ mlir::Value genLibSplitComplexArgsCall(fir::FirOpBuilder &builder,
762813 cplx2, /* isImagPart=*/ true );
763814 splitArgs.push_back (imag2);
764815
765- return genLibCall (builder, loc, libFuncName, getSplitComplexArgsType (),
766- splitArgs);
816+ return genLibCall (builder, loc, mathOp, getSplitComplexArgsType (), splitArgs);
767817}
768818
769819template <typename T>
770820mlir::Value genMathOp (fir::FirOpBuilder &builder, mlir::Location loc,
771- llvm::StringRef mathLibFuncName ,
821+ const MathOperation &mathOp ,
772822 mlir::FunctionType mathLibFuncType,
773823 llvm::ArrayRef<mlir::Value> args) {
774824 // TODO: we have to annotate the math operations with flags
@@ -791,13 +841,14 @@ mlir::Value genMathOp(fir::FirOpBuilder &builder, mlir::Location loc,
791841 // can be also lowered to libm calls for "fast" and "relaxed"
792842 // modes.
793843 mlir::Value result;
844+ llvm::StringRef mathLibFuncName = mathOp.runtimeFunc ;
794845 if (mathRuntimeVersion == preciseVersion &&
795846 // Some operations do not have to be lowered as conservative
796847 // calls, since they do not affect strict FP behavior.
797848 // For example, purely integer operations like exponentiation
798849 // with integer operands fall into this class.
799850 !mathLibFuncName.empty ()) {
800- result = genLibCall (builder, loc, mathLibFuncName , mathLibFuncType, args);
851+ result = genLibCall (builder, loc, mathOp , mathLibFuncType, args);
801852 } else {
802853 LLVM_DEBUG (llvm::dbgs () << " Generating '" << mathLibFuncName
803854 << " ' operation with type " ;
@@ -810,7 +861,7 @@ mlir::Value genMathOp(fir::FirOpBuilder &builder, mlir::Location loc,
810861
811862template <typename T>
812863mlir::Value genComplexMathOp (fir::FirOpBuilder &builder, mlir::Location loc,
813- llvm::StringRef mathLibFuncName ,
864+ const MathOperation &mathOp ,
814865 mlir::FunctionType mathLibFuncType,
815866 llvm::ArrayRef<mlir::Value> args) {
816867 mlir::Value result;
@@ -819,11 +870,12 @@ mlir::Value genComplexMathOp(fir::FirOpBuilder &builder, mlir::Location loc,
819870
820871 // If we have libm functions, we can attempt to generate the more precise
821872 // version of the complex math operation.
873+ llvm::StringRef mathLibFuncName = mathOp.runtimeFunc ;
822874 if (!mathLibFuncName.empty ()) {
823875 // If we enabled MLIR complex or can use approximate operations, we should
824876 // NOT use libm.
825877 if (!forceMlirComplex && !canUseApprox) {
826- result = genLibCall (builder, loc, mathLibFuncName , mathLibFuncType, args);
878+ result = genLibCall (builder, loc, mathOp , mathLibFuncType, args);
827879 LLVM_DEBUG (result.dump (); llvm::dbgs () << " \n " );
828880 return result;
829881 }
@@ -863,6 +915,10 @@ mlir::Value genComplexMathOp(fir::FirOpBuilder &builder, mlir::Location loc,
863915// / TODO: support remaining Fortran math intrinsics.
864916// / See https://gcc.gnu.org/onlinedocs/gcc-12.1.0/gfortran/\
865917/// Intrinsic-Procedures.html for a reference.
918+ constexpr auto FuncTypeReal16Real16 = genFuncType<Ty::Real<16 >, Ty::Real<16 >>;
919+ constexpr auto FuncTypeReal16Complex16 =
920+ genFuncType<Ty::Real<16 >, Ty::Complex<16 >>;
921+
866922static constexpr MathOperation mathOperations[] = {
867923 {" abs" , " fabsf" , genFuncType<Ty::Real<4 >, Ty::Real<4 >>,
868924 genMathOp<mlir::math::AbsFOp>},
@@ -874,6 +930,7 @@ static constexpr MathOperation mathOperations[] = {
874930 genComplexMathOp<mlir::complex ::AbsOp>},
875931 {" abs" , " cabs" , genFuncType<Ty::Real<8 >, Ty::Complex<8 >>,
876932 genComplexMathOp<mlir::complex ::AbsOp>},
933+ {" abs" , RTNAME_STRING (CAbsF128), FuncTypeReal16Complex16, genLibF128Call},
877934 {" acos" , " acosf" , genFuncType<Ty::Real<4 >, Ty::Real<4 >>, genLibCall},
878935 {" acos" , " acos" , genFuncType<Ty::Real<8 >, Ty::Real<8 >>, genLibCall},
879936 {" acos" , " cacosf" , genFuncType<Ty::Complex<4 >, Ty::Complex<4 >>, genLibCall},
@@ -1110,6 +1167,7 @@ static constexpr MathOperation mathOperations[] = {
11101167 genMathOp<mlir::math::SinOp>},
11111168 {" sin" , " sin" , genFuncType<Ty::Real<8 >, Ty::Real<8 >>,
11121169 genMathOp<mlir::math::SinOp>},
1170+ {" sin" , RTNAME_STRING (SinF128), FuncTypeReal16Real16, genLibF128Call},
11131171 {" sin" , " csinf" , genFuncType<Ty::Complex<4 >, Ty::Complex<4 >>,
11141172 genComplexMathOp<mlir::complex ::SinOp>},
11151173 {" sin" , " csin" , genFuncType<Ty::Complex<8 >, Ty::Complex<8 >>,
@@ -1122,6 +1180,7 @@ static constexpr MathOperation mathOperations[] = {
11221180 genMathOp<mlir::math::SqrtOp>},
11231181 {" sqrt" , " sqrt" , genFuncType<Ty::Real<8 >, Ty::Real<8 >>,
11241182 genMathOp<mlir::math::SqrtOp>},
1183+ {" sqrt" , RTNAME_STRING (SqrtF128), FuncTypeReal16Real16, genLibF128Call},
11251184 {" sqrt" , " csqrtf" , genFuncType<Ty::Complex<4 >, Ty::Complex<4 >>,
11261185 genComplexMathOp<mlir::complex ::SqrtOp>},
11271186 {" sqrt" , " csqrt" , genFuncType<Ty::Complex<8 >, Ty::Complex<8 >>,
@@ -1345,27 +1404,9 @@ static void checkPrecisionLoss(llvm::StringRef name,
13451404 // lowering and could be used here. Emit an error and continue
13461405 // generating the code with the narrowing cast so that the user
13471406 // can get a complete list of the problematic intrinsic calls.
1348- std::string message (" not yet implemented: no math runtime available for '" );
1349- llvm::raw_string_ostream sstream (message);
1350- if (name == " pow" ) {
1351- assert (funcType.getNumInputs () == 2 && " power operator has two arguments" );
1352- std::string displayName{" ** " };
1353- sstream << numericMlirTypeToFortran (builder, funcType.getInput (0 ), loc,
1354- displayName)
1355- << displayName
1356- << numericMlirTypeToFortran (builder, funcType.getInput (1 ), loc,
1357- displayName);
1358- } else {
1359- sstream << name.upper () << " (" ;
1360- if (funcType.getNumInputs () > 0 )
1361- sstream << numericMlirTypeToFortran (builder, funcType.getInput (0 ), loc,
1362- name);
1363- for (mlir::Type argType : funcType.getInputs ().drop_front ()) {
1364- sstream << " , " << numericMlirTypeToFortran (builder, argType, loc, name);
1365- }
1366- sstream << " )" ;
1367- }
1368- sstream << " '" ;
1407+ std::string message = prettyPrintIntrinsicName (
1408+ builder, loc, " not yet implemented: no math runtime available for '" ,
1409+ name, " '" , funcType);
13691410 mlir::emitError (loc, message);
13701411}
13711412
@@ -1887,7 +1928,7 @@ IntrinsicLibrary::getRuntimeCallGenerator(llvm::StringRef name,
18871928 for (auto [fst, snd] : llvm::zip (actualFuncType.getInputs (), args))
18881929 convertedArguments.push_back (builder.createConvert (loc, fst, snd));
18891930 mlir::Value result = mathOp->funcGenerator (
1890- builder, loc, mathOp-> runtimeFunc , actualFuncType, convertedArguments);
1931+ builder, loc, * mathOp, actualFuncType, convertedArguments);
18911932 mlir::Type soughtType = soughtFuncType.getResult (0 );
18921933 return builder.createConvert (loc, soughtType, result);
18931934 };
0 commit comments