diff --git a/flang/include/flang/Optimizer/Builder/IntrinsicCall.h b/flang/include/flang/Optimizer/Builder/IntrinsicCall.h --- a/flang/include/flang/Optimizer/Builder/IntrinsicCall.h +++ b/flang/include/flang/Optimizer/Builder/IntrinsicCall.h @@ -10,8 +10,14 @@ #define FORTRAN_LOWER_INTRINSICCALL_H #include "flang/Optimizer/Builder/FIRBuilder.h" +#include "flang/Optimizer/Builder/Runtime/Character.h" +#include "flang/Optimizer/Builder/Runtime/Numeric.h" #include "flang/Optimizer/Builder/Runtime/RTBuilder.h" +#include "flang/Runtime/entry-names.h" #include "flang/Runtime/iostat.h" +#include "mlir/Dialect/Complex/IR/Complex.h" +#include "mlir/Dialect/LLVMIR/LLVMDialect.h" +#include "mlir/Dialect/Math/IR/Math.h" #include namespace fir { @@ -310,10 +316,6 @@ /// is ignored because this is already reflected in the result type. mlir::Value genConversion(mlir::Type, llvm::ArrayRef); - // PPC intrinsic handlers. - template - void genMtfsf(llvm::ArrayRef); - /// In the template helper below: /// - "FN func" is a callback to generate the related intrinsic runtime call. /// - "FD funcDim" is a callback to generate the "dim" runtime call. @@ -550,6 +552,730 @@ return mlir::FunctionType::get(context, argTypes, {resType}); } +const IntrinsicHandler *findIntrinsicHandler(llvm::StringRef name); + +mlir::Value genLibCall(fir::FirOpBuilder &builder, mlir::Location loc, + llvm::StringRef libFuncName, + mlir::FunctionType libFuncType, + llvm::ArrayRef args); + +template +mlir::Value genMathOp(fir::FirOpBuilder &builder, mlir::Location loc, + llvm::StringRef mathLibFuncName, + mlir::FunctionType mathLibFuncType, + llvm::ArrayRef args); + +template +mlir::Value genComplexMathOp(fir::FirOpBuilder &builder, mlir::Location loc, + llvm::StringRef mathLibFuncName, + mlir::FunctionType mathLibFuncType, + llvm::ArrayRef args); + +mlir::Value genLibSplitComplexArgsCall(fir::FirOpBuilder &builder, + mlir::Location loc, + llvm::StringRef libFuncName, + mlir::FunctionType libFuncType, + llvm::ArrayRef args); + +constexpr auto asValue = fir::LowerIntrinsicArgAs::Value; +constexpr auto asAddr = fir::LowerIntrinsicArgAs::Addr; +constexpr auto asBox = fir::LowerIntrinsicArgAs::Box; +constexpr auto asInquired = fir::LowerIntrinsicArgAs::Inquired; + +using I = IntrinsicLibrary; + +/// Flag to indicate that an intrinsic argument has to be handled as +/// being dynamically optional (e.g. special handling when actual +/// argument is an optional variable in the current scope). +static constexpr bool handleDynamicOptional = true; + +/// Table that drives the fir generation depending on the intrinsic or intrinsic +/// module procedure one to one mapping with Fortran arguments. If no mapping is +/// defined here for a generic intrinsic, genRuntimeCall will be called +/// to look for a match in the runtime a emit a call. Note that the argument +/// lowering rules for an intrinsic need to be provided only if at least one +/// argument must not be lowered by value. In which case, the lowering rules +/// should be provided for all the intrinsic arguments for completeness. +static constexpr IntrinsicHandler handlers[]{ + {"abort", &I::genAbort}, + {"abs", &I::genAbs}, + {"achar", &I::genChar}, + {"adjustl", + &I::genAdjustRtCall, + {{{"string", asAddr}}}, + /*isElemental=*/true}, + {"adjustr", + &I::genAdjustRtCall, + {{{"string", asAddr}}}, + /*isElemental=*/true}, + {"aimag", &I::genAimag}, + {"aint", &I::genAint}, + {"all", + &I::genAll, + {{{"mask", asAddr}, {"dim", asValue}}}, + /*isElemental=*/false}, + {"allocated", + &I::genAllocated, + {{{"array", asInquired}, {"scalar", asInquired}}}, + /*isElemental=*/false}, + {"anint", &I::genAnint}, + {"any", + &I::genAny, + {{{"mask", asAddr}, {"dim", asValue}}}, + /*isElemental=*/false}, + {"associated", + &I::genAssociated, + {{{"pointer", asInquired}, {"target", asInquired}}}, + /*isElemental=*/false}, + {"atand", &I::genAtand}, + {"bessel_jn", + &I::genBesselJn, + {{{"n1", asValue}, {"n2", asValue}, {"x", asValue}}}, + /*isElemental=*/false}, + {"bessel_yn", + &I::genBesselYn, + {{{"n1", asValue}, {"n2", asValue}, {"x", asValue}}}, + /*isElemental=*/false}, + {"bge", &I::genBitwiseCompare}, + {"bgt", &I::genBitwiseCompare}, + {"ble", &I::genBitwiseCompare}, + {"blt", &I::genBitwiseCompare}, + {"btest", &I::genBtest}, + {"c_associated_c_funptr", + &I::genCAssociatedCFunPtr, + {{{"c_ptr_1", asAddr}, {"c_ptr_2", asAddr, handleDynamicOptional}}}, + /*isElemental=*/false}, + {"c_associated_c_ptr", + &I::genCAssociatedCPtr, + {{{"c_ptr_1", asAddr}, {"c_ptr_2", asAddr, handleDynamicOptional}}}, + /*isElemental=*/false}, + {"c_f_pointer", + &I::genCFPointer, + {{{"cptr", asValue}, + {"fptr", asInquired}, + {"shape", asAddr, handleDynamicOptional}}}, + /*isElemental=*/false}, + {"c_funloc", &I::genCFunLoc, {{{"x", asBox}}}, /*isElemental=*/false}, + {"c_loc", &I::genCLoc, {{{"x", asBox}}}, /*isElemental=*/false}, + {"ceiling", &I::genCeiling}, + {"char", &I::genChar}, + {"cmplx", + &I::genCmplx, + {{{"x", asValue}, {"y", asValue, handleDynamicOptional}}}}, + {"command_argument_count", &I::genCommandArgumentCount}, + {"conjg", &I::genConjg}, + {"count", + &I::genCount, + {{{"mask", asAddr}, {"dim", asValue}, {"kind", asValue}}}, + /*isElemental=*/false}, + {"cpu_time", + &I::genCpuTime, + {{{"time", asAddr}}}, + /*isElemental=*/false}, + {"cshift", + &I::genCshift, + {{{"array", asAddr}, {"shift", asAddr}, {"dim", asValue}}}, + /*isElemental=*/false}, + {"date_and_time", + &I::genDateAndTime, + {{{"date", asAddr, handleDynamicOptional}, + {"time", asAddr, handleDynamicOptional}, + {"zone", asAddr, handleDynamicOptional}, + {"values", asBox, handleDynamicOptional}}}, + /*isElemental=*/false}, + {"dble", &I::genConversion}, + {"dim", &I::genDim}, + {"dot_product", + &I::genDotProduct, + {{{"vector_a", asBox}, {"vector_b", asBox}}}, + /*isElemental=*/false}, + {"dprod", &I::genDprod}, + {"dshiftl", &I::genDshiftl}, + {"dshiftr", &I::genDshiftr}, + {"eoshift", + &I::genEoshift, + {{{"array", asBox}, + {"shift", asAddr}, + {"boundary", asBox, handleDynamicOptional}, + {"dim", asValue}}}, + /*isElemental=*/false}, + {"exit", + &I::genExit, + {{{"status", asValue, handleDynamicOptional}}}, + /*isElemental=*/false}, + {"exponent", &I::genExponent}, + {"extends_type_of", + &I::genExtendsTypeOf, + {{{"a", asBox}, {"mold", asBox}}}, + /*isElemental=*/false}, + {"findloc", + &I::genFindloc, + {{{"array", asBox}, + {"value", asAddr}, + {"dim", asValue}, + {"mask", asBox, handleDynamicOptional}, + {"kind", asValue}, + {"back", asValue, handleDynamicOptional}}}, + /*isElemental=*/false}, + {"floor", &I::genFloor}, + {"fraction", &I::genFraction}, + {"get_command", + &I::genGetCommand, + {{{"command", asBox, handleDynamicOptional}, + {"length", asBox, handleDynamicOptional}, + {"status", asAddr, handleDynamicOptional}, + {"errmsg", asBox, handleDynamicOptional}}}, + /*isElemental=*/false}, + {"get_command_argument", + &I::genGetCommandArgument, + {{{"number", asValue}, + {"value", asBox, handleDynamicOptional}, + {"length", asBox, handleDynamicOptional}, + {"status", asAddr, handleDynamicOptional}, + {"errmsg", asBox, handleDynamicOptional}}}, + /*isElemental=*/false}, + {"get_environment_variable", + &I::genGetEnvironmentVariable, + {{{"name", asBox}, + {"value", asBox, handleDynamicOptional}, + {"length", asBox, handleDynamicOptional}, + {"status", asAddr, handleDynamicOptional}, + {"trim_name", asAddr, handleDynamicOptional}, + {"errmsg", asBox, handleDynamicOptional}}}, + /*isElemental=*/false}, + {"iachar", &I::genIchar}, + {"iall", + &I::genIall, + {{{"array", asBox}, + {"dim", asValue}, + {"mask", asBox, handleDynamicOptional}}}, + /*isElemental=*/false}, + {"iand", &I::genIand}, + {"iany", + &I::genIany, + {{{"array", asBox}, + {"dim", asValue}, + {"mask", asBox, handleDynamicOptional}}}, + /*isElemental=*/false}, + {"ibclr", &I::genIbclr}, + {"ibits", &I::genIbits}, + {"ibset", &I::genIbset}, + {"ichar", &I::genIchar}, + {"ieee_class_eq", &I::genIeeeTypeCompare}, + {"ieee_class_ne", &I::genIeeeTypeCompare}, + {"ieee_is_finite", &I::genIeeeIsFinite}, + {"ieee_is_nan", &I::genIsNan}, + {"ieee_is_normal", &I::genIeeeIsNormal}, + {"ieee_round_eq", &I::genIeeeTypeCompare}, + {"ieee_round_ne", &I::genIeeeTypeCompare}, + {"ieor", &I::genIeor}, + {"index", + &I::genIndex, + {{{"string", asAddr}, + {"substring", asAddr}, + {"back", asValue, handleDynamicOptional}, + {"kind", asValue}}}}, + {"ior", &I::genIor}, + {"iparity", + &I::genIparity, + {{{"array", asBox}, + {"dim", asValue}, + {"mask", asBox, handleDynamicOptional}}}, + /*isElemental=*/false}, + {"is_contiguous", + &I::genIsContiguous, + {{{"array", asBox}}}, + /*isElemental=*/false}, + {"is_iostat_end", &I::genIsIostatValue}, + {"is_iostat_eor", &I::genIsIostatValue}, + {"ishft", &I::genIshft}, + {"ishftc", &I::genIshftc}, + {"isnan", &I::genIsNan}, + {"lbound", + &I::genLbound, + {{{"array", asInquired}, {"dim", asValue}, {"kind", asValue}}}, + /*isElemental=*/false}, + {"leadz", &I::genLeadz}, + {"len", + &I::genLen, + {{{"string", asInquired}, {"kind", asValue}}}, + /*isElemental=*/false}, + {"len_trim", &I::genLenTrim}, + {"lge", &I::genCharacterCompare}, + {"lgt", &I::genCharacterCompare}, + {"lle", &I::genCharacterCompare}, + {"llt", &I::genCharacterCompare}, + {"loc", &I::genLoc, {{{"x", asBox}}}, /*isElemental=*/false}, + {"maskl", &I::genMask}, + {"maskr", &I::genMask}, + {"matmul", + &I::genMatmul, + {{{"matrix_a", asAddr}, {"matrix_b", asAddr}}}, + /*isElemental=*/false}, + {"matmul_transpose", + &I::genMatmulTranspose, + {{{"matrix_a", asAddr}, {"matrix_b", asAddr}}}, + /*isElemental=*/false}, + {"max", &I::genExtremum}, + {"maxloc", + &I::genMaxloc, + {{{"array", asBox}, + {"dim", asValue}, + {"mask", asBox, handleDynamicOptional}, + {"kind", asValue}, + {"back", asValue, handleDynamicOptional}}}, + /*isElemental=*/false}, + {"maxval", + &I::genMaxval, + {{{"array", asBox}, + {"dim", asValue}, + {"mask", asBox, handleDynamicOptional}}}, + /*isElemental=*/false}, + {"merge", &I::genMerge}, + {"merge_bits", &I::genMergeBits}, + {"min", &I::genExtremum}, + {"minloc", + &I::genMinloc, + {{{"array", asBox}, + {"dim", asValue}, + {"mask", asBox, handleDynamicOptional}, + {"kind", asValue}, + {"back", asValue, handleDynamicOptional}}}, + /*isElemental=*/false}, + {"minval", + &I::genMinval, + {{{"array", asBox}, + {"dim", asValue}, + {"mask", asBox, handleDynamicOptional}}}, + /*isElemental=*/false}, + {"mod", &I::genMod}, + {"modulo", &I::genModulo}, + {"move_alloc", + &I::genMoveAlloc, + {{{"from", asInquired}, + {"to", asInquired}, + {"status", asAddr, handleDynamicOptional}, + {"errMsg", asBox, handleDynamicOptional}}}, + /*isElemental=*/false}, + {"mvbits", + &I::genMvbits, + {{{"from", asValue}, + {"frompos", asValue}, + {"len", asValue}, + {"to", asAddr}, + {"topos", asValue}}}}, + {"nearest", &I::genNearest}, + {"nint", &I::genNint}, + {"norm2", + &I::genNorm2, + {{{"array", asBox}, {"dim", asValue}}}, + /*isElemental=*/false}, + {"not", &I::genNot}, + {"null", &I::genNull, {{{"mold", asInquired}}}, /*isElemental=*/false}, + {"pack", + &I::genPack, + {{{"array", asBox}, + {"mask", asBox}, + {"vector", asBox, handleDynamicOptional}}}, + /*isElemental=*/false}, + {"parity", + &I::genParity, + {{{"mask", asBox}, {"dim", asValue}}}, + /*isElemental=*/false}, + {"popcnt", &I::genPopcnt}, + {"poppar", &I::genPoppar}, + {"present", + &I::genPresent, + {{{"a", asInquired}}}, + /*isElemental=*/false}, + {"product", + &I::genProduct, + {{{"array", asBox}, + {"dim", asValue}, + {"mask", asBox, handleDynamicOptional}}}, + /*isElemental=*/false}, + {"random_init", + &I::genRandomInit, + {{{"repeatable", asValue}, {"image_distinct", asValue}}}, + /*isElemental=*/false}, + {"random_number", + &I::genRandomNumber, + {{{"harvest", asBox}}}, + /*isElemental=*/false}, + {"random_seed", + &I::genRandomSeed, + {{{"size", asBox, handleDynamicOptional}, + {"put", asBox, handleDynamicOptional}, + {"get", asBox, handleDynamicOptional}}}, + /*isElemental=*/false}, + {"reduce", + &I::genReduce, + {{{"array", asBox}, + {"operation", asAddr}, + {"dim", asValue}, + {"mask", asBox, handleDynamicOptional}, + {"identity", asValue}, + {"ordered", asValue}}}, + /*isElemental=*/false}, + {"repeat", + &I::genRepeat, + {{{"string", asAddr}, {"ncopies", asValue}}}, + /*isElemental=*/false}, + {"reshape", + &I::genReshape, + {{{"source", asBox}, + {"shape", asBox}, + {"pad", asBox, handleDynamicOptional}, + {"order", asBox, handleDynamicOptional}}}, + /*isElemental=*/false}, + {"rrspacing", &I::genRRSpacing}, + {"same_type_as", + &I::genSameTypeAs, + {{{"a", asBox}, {"b", asBox}}}, + /*isElemental=*/false}, + {"scale", + &I::genScale, + {{{"x", asValue}, {"i", asValue}}}, + /*isElemental=*/true}, + {"scan", + &I::genScan, + {{{"string", asAddr}, + {"set", asAddr}, + {"back", asValue, handleDynamicOptional}, + {"kind", asValue}}}, + /*isElemental=*/true}, + {"selected_int_kind", + &I::genSelectedIntKind, + {{{"scalar", asAddr}}}, + /*isElemental=*/false}, + {"selected_real_kind", + &I::genSelectedRealKind, + {{{"precision", asAddr, handleDynamicOptional}, + {"range", asAddr, handleDynamicOptional}, + {"radix", asAddr, handleDynamicOptional}}}, + /*isElemental=*/false}, + {"set_exponent", &I::genSetExponent}, + {"shifta", &I::genShiftA}, + {"shiftl", &I::genShift}, + {"shiftr", &I::genShift}, + {"sign", &I::genSign}, + {"size", + &I::genSize, + {{{"array", asBox}, + {"dim", asAddr, handleDynamicOptional}, + {"kind", asValue}}}, + /*isElemental=*/false}, + {"spacing", &I::genSpacing}, + {"spread", + &I::genSpread, + {{{"source", asBox}, {"dim", asValue}, {"ncopies", asValue}}}, + /*isElemental=*/false}, + {"storage_size", + &I::genStorageSize, + {{{"a", asInquired}, {"kind", asValue}}}, + /*isElemental=*/false}, + {"sum", + &I::genSum, + {{{"array", asBox}, + {"dim", asValue}, + {"mask", asBox, handleDynamicOptional}}}, + /*isElemental=*/false}, + {"system_clock", + &I::genSystemClock, + {{{"count", asAddr}, {"count_rate", asAddr}, {"count_max", asAddr}}}, + /*isElemental=*/false}, + {"trailz", &I::genTrailz}, + {"transfer", + &I::genTransfer, + {{{"source", asAddr}, {"mold", asAddr}, {"size", asValue}}}, + /*isElemental=*/false}, + {"transpose", + &I::genTranspose, + {{{"matrix", asAddr}}}, + /*isElemental=*/false}, + {"trim", &I::genTrim, {{{"string", asAddr}}}, /*isElemental=*/false}, + {"ubound", + &I::genUbound, + {{{"array", asBox}, {"dim", asValue}, {"kind", asValue}}}, + /*isElemental=*/false}, + {"unpack", + &I::genUnpack, + {{{"vector", asBox}, {"mask", asBox}, {"field", asBox}}}, + /*isElemental=*/false}, + {"verify", + &I::genVerify, + {{{"string", asAddr}, + {"set", asAddr}, + {"back", asValue, handleDynamicOptional}, + {"kind", asValue}}}, + /*isElemental=*/true}, +}; + +/// Mapping between mathematical intrinsic operations and MLIR operations +/// of some appropriate dialect (math, complex, etc.) or libm calls. +/// TODO: support remaining Fortran math intrinsics. +/// See https://gcc.gnu.org/onlinedocs/gcc-12.1.0/gfortran/\ +/// Intrinsic-Procedures.html for a reference. +static constexpr MathOperation mathOperations[] = { + {"abs", "fabsf", genFuncType, Ty::Real<4>>, + genMathOp}, + {"abs", "fabs", genFuncType, Ty::Real<8>>, + genMathOp}, + {"abs", "llvm.fabs.f128", genFuncType, Ty::Real<16>>, + genMathOp}, + {"abs", "cabsf", genFuncType, Ty::Complex<4>>, + genComplexMathOp}, + {"abs", "cabs", genFuncType, Ty::Complex<8>>, + genComplexMathOp}, + {"acos", "acosf", genFuncType, Ty::Real<4>>, genLibCall}, + {"acos", "acos", genFuncType, Ty::Real<8>>, genLibCall}, + {"acos", "cacosf", genFuncType, Ty::Complex<4>>, genLibCall}, + {"acos", "cacos", genFuncType, Ty::Complex<8>>, genLibCall}, + {"acosh", "acoshf", genFuncType, Ty::Real<4>>, genLibCall}, + {"acosh", "acosh", genFuncType, Ty::Real<8>>, genLibCall}, + {"acosh", "cacoshf", genFuncType, Ty::Complex<4>>, + genLibCall}, + {"acosh", "cacosh", genFuncType, Ty::Complex<8>>, + genLibCall}, + // llvm.trunc behaves the same way as libm's trunc. + {"aint", "llvm.trunc.f32", genFuncType, Ty::Real<4>>, + genLibCall}, + {"aint", "llvm.trunc.f64", genFuncType, Ty::Real<8>>, + genLibCall}, + {"aint", "llvm.trunc.f80", genFuncType, Ty::Real<10>>, + genLibCall}, + // llvm.round behaves the same way as libm's round. + {"anint", "llvm.round.f32", genFuncType, Ty::Real<4>>, + genMathOp}, + {"anint", "llvm.round.f64", genFuncType, Ty::Real<8>>, + genMathOp}, + {"anint", "llvm.round.f80", genFuncType, Ty::Real<10>>, + genMathOp}, + {"asin", "asinf", genFuncType, Ty::Real<4>>, genLibCall}, + {"asin", "asin", genFuncType, Ty::Real<8>>, genLibCall}, + {"asin", "casinf", genFuncType, Ty::Complex<4>>, genLibCall}, + {"asin", "casin", genFuncType, Ty::Complex<8>>, genLibCall}, + {"asinh", "asinhf", genFuncType, Ty::Real<4>>, genLibCall}, + {"asinh", "asinh", genFuncType, Ty::Real<8>>, genLibCall}, + {"asinh", "casinhf", genFuncType, Ty::Complex<4>>, + genLibCall}, + {"asinh", "casinh", genFuncType, Ty::Complex<8>>, + genLibCall}, + {"atan", "atanf", genFuncType, Ty::Real<4>>, + genMathOp}, + {"atan", "atan", genFuncType, Ty::Real<8>>, + genMathOp}, + {"atan", "catanf", genFuncType, Ty::Complex<4>>, genLibCall}, + {"atan", "catan", genFuncType, Ty::Complex<8>>, genLibCall}, + {"atan2", "atan2f", genFuncType, Ty::Real<4>, Ty::Real<4>>, + genMathOp}, + {"atan2", "atan2", genFuncType, Ty::Real<8>, Ty::Real<8>>, + genMathOp}, + {"atanh", "atanhf", genFuncType, Ty::Real<4>>, genLibCall}, + {"atanh", "atanh", genFuncType, Ty::Real<8>>, genLibCall}, + {"atanh", "catanhf", genFuncType, Ty::Complex<4>>, + genLibCall}, + {"atanh", "catanh", genFuncType, Ty::Complex<8>>, + genLibCall}, + {"bessel_j0", "j0f", genFuncType, Ty::Real<4>>, genLibCall}, + {"bessel_j0", "j0", genFuncType, Ty::Real<8>>, genLibCall}, + {"bessel_j1", "j1f", genFuncType, Ty::Real<4>>, genLibCall}, + {"bessel_j1", "j1", genFuncType, Ty::Real<8>>, genLibCall}, + {"bessel_jn", "jnf", genFuncType, Ty::Integer<4>, Ty::Real<4>>, + genLibCall}, + {"bessel_jn", "jn", genFuncType, Ty::Integer<4>, Ty::Real<8>>, + genLibCall}, + {"bessel_y0", "y0f", genFuncType, Ty::Real<4>>, genLibCall}, + {"bessel_y0", "y0", genFuncType, Ty::Real<8>>, genLibCall}, + {"bessel_y1", "y1f", genFuncType, Ty::Real<4>>, genLibCall}, + {"bessel_y1", "y1", genFuncType, Ty::Real<8>>, genLibCall}, + {"bessel_yn", "ynf", genFuncType, Ty::Integer<4>, Ty::Real<4>>, + genLibCall}, + {"bessel_yn", "yn", genFuncType, Ty::Integer<4>, Ty::Real<8>>, + genLibCall}, + // math::CeilOp returns a real, while Fortran CEILING returns integer. + {"ceil", "ceilf", genFuncType, Ty::Real<4>>, + genMathOp}, + {"ceil", "ceil", genFuncType, Ty::Real<8>>, + genMathOp}, + {"cos", "cosf", genFuncType, Ty::Real<4>>, + genMathOp}, + {"cos", "cos", genFuncType, Ty::Real<8>>, + genMathOp}, + {"cos", "ccosf", genFuncType, Ty::Complex<4>>, + genComplexMathOp}, + {"cos", "ccos", genFuncType, Ty::Complex<8>>, + genComplexMathOp}, + {"cosh", "coshf", genFuncType, Ty::Real<4>>, genLibCall}, + {"cosh", "cosh", genFuncType, Ty::Real<8>>, genLibCall}, + {"cosh", "ccoshf", genFuncType, Ty::Complex<4>>, genLibCall}, + {"cosh", "ccosh", genFuncType, Ty::Complex<8>>, genLibCall}, + {"divc", + {}, + genFuncType, Ty::Complex<2>, Ty::Complex<2>>, + genComplexMathOp}, + {"divc", + {}, + genFuncType, Ty::Complex<3>, Ty::Complex<3>>, + genComplexMathOp}, + {"divc", "__divsc3", + genFuncType, Ty::Complex<4>, Ty::Complex<4>>, + genLibSplitComplexArgsCall}, + {"divc", "__divdc3", + genFuncType, Ty::Complex<8>, Ty::Complex<8>>, + genLibSplitComplexArgsCall}, + {"divc", "__divxc3", + genFuncType, Ty::Complex<10>, Ty::Complex<10>>, + genLibSplitComplexArgsCall}, + {"divc", "__divtc3", + genFuncType, Ty::Complex<16>, Ty::Complex<16>>, + genLibSplitComplexArgsCall}, + {"erf", "erff", genFuncType, Ty::Real<4>>, + genMathOp}, + {"erf", "erf", genFuncType, Ty::Real<8>>, + genMathOp}, + {"erfc", "erfcf", genFuncType, Ty::Real<4>>, genLibCall}, + {"erfc", "erfc", genFuncType, Ty::Real<8>>, genLibCall}, + {"exp", "expf", genFuncType, Ty::Real<4>>, + genMathOp}, + {"exp", "exp", genFuncType, Ty::Real<8>>, + genMathOp}, + {"exp", "cexpf", genFuncType, Ty::Complex<4>>, + genComplexMathOp}, + {"exp", "cexp", genFuncType, Ty::Complex<8>>, + genComplexMathOp}, + // math::FloorOp returns a real, while Fortran FLOOR returns integer. + {"floor", "floorf", genFuncType, Ty::Real<4>>, + genMathOp}, + {"floor", "floor", genFuncType, Ty::Real<8>>, + genMathOp}, + {"fma", "llvm.fma.f32", + genFuncType, Ty::Real<4>, Ty::Real<4>, Ty::Real<4>>, + genMathOp}, + {"fma", "llvm.fma.f64", + genFuncType, Ty::Real<8>, Ty::Real<8>, Ty::Real<8>>, + genMathOp}, + {"gamma", "tgammaf", genFuncType, Ty::Real<4>>, genLibCall}, + {"gamma", "tgamma", genFuncType, Ty::Real<8>>, genLibCall}, + {"hypot", "hypotf", genFuncType, Ty::Real<4>, Ty::Real<4>>, + genLibCall}, + {"hypot", "hypot", genFuncType, Ty::Real<8>, Ty::Real<8>>, + genLibCall}, + {"log", "logf", genFuncType, Ty::Real<4>>, + genMathOp}, + {"log", "log", genFuncType, Ty::Real<8>>, + genMathOp}, + {"log", "clogf", genFuncType, Ty::Complex<4>>, + genComplexMathOp}, + {"log", "clog", genFuncType, Ty::Complex<8>>, + genComplexMathOp}, + {"log10", "log10f", genFuncType, Ty::Real<4>>, + genMathOp}, + {"log10", "log10", genFuncType, Ty::Real<8>>, + genMathOp}, + {"log_gamma", "lgammaf", genFuncType, Ty::Real<4>>, genLibCall}, + {"log_gamma", "lgamma", genFuncType, Ty::Real<8>>, genLibCall}, + // llvm.lround behaves the same way as libm's lround. + {"nint", "llvm.lround.i64.f64", genFuncType, Ty::Real<8>>, + genLibCall}, + {"nint", "llvm.lround.i64.f32", genFuncType, Ty::Real<4>>, + genLibCall}, + {"nint", "llvm.lround.i32.f64", genFuncType, Ty::Real<8>>, + genLibCall}, + {"nint", "llvm.lround.i32.f32", genFuncType, Ty::Real<4>>, + genLibCall}, + {"pow", + {}, + genFuncType, Ty::Integer<1>, Ty::Integer<1>>, + genMathOp}, + {"pow", + {}, + genFuncType, Ty::Integer<2>, Ty::Integer<2>>, + genMathOp}, + {"pow", + {}, + genFuncType, Ty::Integer<4>, Ty::Integer<4>>, + genMathOp}, + {"pow", + {}, + genFuncType, Ty::Integer<8>, Ty::Integer<8>>, + genMathOp}, + {"pow", "powf", genFuncType, Ty::Real<4>, Ty::Real<4>>, + genMathOp}, + {"pow", "pow", genFuncType, Ty::Real<8>, Ty::Real<8>>, + genMathOp}, + {"pow", "cpowf", + genFuncType, Ty::Complex<4>, Ty::Complex<4>>, + genComplexMathOp}, + {"pow", "cpow", genFuncType, Ty::Complex<8>, Ty::Complex<8>>, + genComplexMathOp}, + {"pow", RTNAME_STRING(FPow4i), + genFuncType, Ty::Real<4>, Ty::Integer<4>>, + genMathOp}, + {"pow", RTNAME_STRING(FPow8i), + genFuncType, Ty::Real<8>, Ty::Integer<4>>, + genMathOp}, + {"pow", RTNAME_STRING(FPow4k), + genFuncType, Ty::Real<4>, Ty::Integer<8>>, + genMathOp}, + {"pow", RTNAME_STRING(FPow8k), + genFuncType, Ty::Real<8>, Ty::Integer<8>>, + genMathOp}, + {"pow", RTNAME_STRING(cpowi), + genFuncType, Ty::Complex<4>, Ty::Integer<4>>, genLibCall}, + {"pow", RTNAME_STRING(zpowi), + genFuncType, Ty::Complex<8>, Ty::Integer<4>>, genLibCall}, + {"pow", RTNAME_STRING(cpowk), + genFuncType, Ty::Complex<4>, Ty::Integer<8>>, genLibCall}, + {"pow", RTNAME_STRING(zpowk), + genFuncType, Ty::Complex<8>, Ty::Integer<8>>, genLibCall}, + {"sign", "copysignf", genFuncType, Ty::Real<4>, Ty::Real<4>>, + genMathOp}, + {"sign", "copysign", genFuncType, Ty::Real<8>, Ty::Real<8>>, + genMathOp}, + {"sign", "copysignl", genFuncType, Ty::Real<10>, Ty::Real<10>>, + genMathOp}, + {"sign", "llvm.copysign.f128", + genFuncType, Ty::Real<16>, Ty::Real<16>>, + genMathOp}, + {"sin", "sinf", genFuncType, Ty::Real<4>>, + genMathOp}, + {"sin", "sin", genFuncType, Ty::Real<8>>, + genMathOp}, + {"sin", "csinf", genFuncType, Ty::Complex<4>>, + genComplexMathOp}, + {"sin", "csin", genFuncType, Ty::Complex<8>>, + genComplexMathOp}, + {"sinh", "sinhf", genFuncType, Ty::Real<4>>, genLibCall}, + {"sinh", "sinh", genFuncType, Ty::Real<8>>, genLibCall}, + {"sinh", "csinhf", genFuncType, Ty::Complex<4>>, genLibCall}, + {"sinh", "csinh", genFuncType, Ty::Complex<8>>, genLibCall}, + {"sqrt", "sqrtf", genFuncType, Ty::Real<4>>, + genMathOp}, + {"sqrt", "sqrt", genFuncType, Ty::Real<8>>, + genMathOp}, + {"sqrt", "csqrtf", genFuncType, Ty::Complex<4>>, + genComplexMathOp}, + {"sqrt", "csqrt", genFuncType, Ty::Complex<8>>, + genComplexMathOp}, + {"tan", "tanf", genFuncType, Ty::Real<4>>, + genMathOp}, + {"tan", "tan", genFuncType, Ty::Real<8>>, + genMathOp}, + {"tan", "ctanf", genFuncType, Ty::Complex<4>>, + genComplexMathOp}, + {"tan", "ctan", genFuncType, Ty::Complex<8>>, + genComplexMathOp}, + {"tanh", "tanhf", genFuncType, Ty::Real<4>>, + genMathOp}, + {"tanh", "tanh", genFuncType, Ty::Real<8>>, + genMathOp}, + {"tanh", "ctanhf", genFuncType, Ty::Complex<4>>, + genComplexMathOp}, + {"tanh", "ctanh", genFuncType, Ty::Complex<8>>, + genComplexMathOp}, +}; + /// Return argument lowering rules for an intrinsic. /// Returns a nullptr if all the intrinsic arguments should be lowered by value. const IntrinsicArgumentLoweringRules * diff --git a/flang/include/flang/Optimizer/Builder/PPCIntrinsicCall.h b/flang/include/flang/Optimizer/Builder/PPCIntrinsicCall.h new file mode 100644 --- /dev/null +++ b/flang/include/flang/Optimizer/Builder/PPCIntrinsicCall.h @@ -0,0 +1,106 @@ +//===-- Builder/PPCIntrinsicCall.h -- lowering of PowerPC intrinsics ------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef FORTRAN_LOWER_PPCINTRINSICCALL_H +#define FORTRAN_LOWER_PPCINTRINSICCALL_H + +#include "flang/Optimizer/Builder/IntrinsicCall.h" +#include "mlir/Dialect/Math/IR/Math.h" + +namespace fir { + +struct PPCIntrinsicLibrary : IntrinsicLibrary { + + // Constructors. + explicit PPCIntrinsicLibrary(fir::FirOpBuilder &builder, mlir::Location loc) + : IntrinsicLibrary(builder, loc) {} + PPCIntrinsicLibrary() = delete; + PPCIntrinsicLibrary(const PPCIntrinsicLibrary &) = delete; + + // PPC intrinsic handlers. + template + void genMtfsf(llvm::ArrayRef); +}; + +const IntrinsicHandler *findPPCIntrinsicHandler(llvm::StringRef name); + +using PI = PPCIntrinsicLibrary; + +// PPC specific intrinsic handlers. +static constexpr IntrinsicHandler ppcHandlers[]{ + {"__ppc_mtfsf", + static_cast(&PI::genMtfsf), + {{{"mask", asValue}, {"r", asValue}}}, + /*isElemental=*/false}, + {"__ppc_mtfsfi", + static_cast(&PI::genMtfsf), + {{{"bf", asValue}, {"i", asValue}}}, + /*isElemental=*/false}, +}; + +static constexpr MathOperation ppcMathOperations[] = { + // fcfi is just another name for fcfid, there is no llvm.ppc.fcfi. + {"__ppc_fcfi", "llvm.ppc.fcfid", genFuncType, Ty::Real<8>>, + genLibCall}, + {"__ppc_fcfid", "llvm.ppc.fcfid", genFuncType, Ty::Real<8>>, + genLibCall}, + {"__ppc_fcfud", "llvm.ppc.fcfud", genFuncType, Ty::Real<8>>, + genLibCall}, + {"__ppc_fctid", "llvm.ppc.fctid", genFuncType, Ty::Real<8>>, + genLibCall}, + {"__ppc_fctidz", "llvm.ppc.fctidz", genFuncType, Ty::Real<8>>, + genLibCall}, + {"__ppc_fctiw", "llvm.ppc.fctiw", genFuncType, Ty::Real<8>>, + genLibCall}, + {"__ppc_fctiwz", "llvm.ppc.fctiwz", genFuncType, Ty::Real<8>>, + genLibCall}, + {"__ppc_fctudz", "llvm.ppc.fctudz", genFuncType, Ty::Real<8>>, + genLibCall}, + {"__ppc_fctuwz", "llvm.ppc.fctuwz", genFuncType, Ty::Real<8>>, + genLibCall}, + {"__ppc_fmadd", "llvm.fma.f32", + genFuncType, Ty::Real<4>, Ty::Real<4>, Ty::Real<4>>, + genMathOp}, + {"__ppc_fmadd", "llvm.fma.f64", + genFuncType, Ty::Real<8>, Ty::Real<8>, Ty::Real<8>>, + genMathOp}, + {"__ppc_fmsub", "llvm.ppc.fmsubs", + genFuncType, Ty::Real<4>, Ty::Real<4>, Ty::Real<4>>, + genLibCall}, + {"__ppc_fmsub", "llvm.ppc.fmsub", + genFuncType, Ty::Real<8>, Ty::Real<8>, Ty::Real<8>>, + genLibCall}, + {"__ppc_fnabs", "llvm.ppc.fnabss", genFuncType, Ty::Real<4>>, + genLibCall}, + {"__ppc_fnabs", "llvm.ppc.fnabs", genFuncType, Ty::Real<8>>, + genLibCall}, + {"__ppc_fnmadd", "llvm.ppc.fnmadds", + genFuncType, Ty::Real<4>, Ty::Real<4>, Ty::Real<4>>, + genLibCall}, + {"__ppc_fnmadd", "llvm.ppc.fnmadd", + genFuncType, Ty::Real<8>, Ty::Real<8>, Ty::Real<8>>, + genLibCall}, + {"__ppc_fnmsub", "llvm.ppc.fnmsub.f32", + genFuncType, Ty::Real<4>, Ty::Real<4>, Ty::Real<4>>, + genLibCall}, + {"__ppc_fnmsub", "llvm.ppc.fnmsub.f64", + genFuncType, Ty::Real<8>, Ty::Real<8>, Ty::Real<8>>, + genLibCall}, + {"__ppc_fre", "llvm.ppc.fre", genFuncType, Ty::Real<8>>, + genLibCall}, + {"__ppc_fres", "llvm.ppc.fres", genFuncType, Ty::Real<4>>, + genLibCall}, + {"__ppc_frsqrte", "llvm.ppc.frsqrte", genFuncType, Ty::Real<8>>, + genLibCall}, + {"__ppc_frsqrtes", "llvm.ppc.frsqrtes", + genFuncType, Ty::Real<4>>, genLibCall}, +}; + +} // namespace fir + +#endif // FORTRAN_LOWER_PPCINTRINSICCALL_H diff --git a/flang/lib/Optimizer/Builder/CMakeLists.txt b/flang/lib/Optimizer/Builder/CMakeLists.txt --- a/flang/lib/Optimizer/Builder/CMakeLists.txt +++ b/flang/lib/Optimizer/Builder/CMakeLists.txt @@ -10,6 +10,7 @@ IntrinsicCall.cpp LowLevelIntrinsics.cpp MutableBox.cpp + PPCIntrinsicCall.cpp Runtime/Allocatable.cpp Runtime/ArrayConstructor.cpp Runtime/Assign.cpp diff --git a/flang/lib/Optimizer/Builder/IntrinsicCall.cpp b/flang/lib/Optimizer/Builder/IntrinsicCall.cpp --- a/flang/lib/Optimizer/Builder/IntrinsicCall.cpp +++ b/flang/lib/Optimizer/Builder/IntrinsicCall.cpp @@ -20,6 +20,7 @@ #include "flang/Optimizer/Builder/Complex.h" #include "flang/Optimizer/Builder/FIRBuilder.h" #include "flang/Optimizer/Builder/MutableBox.h" +#include "flang/Optimizer/Builder/PPCIntrinsicCall.h" #include "flang/Optimizer/Builder/Runtime/Allocatable.h" #include "flang/Optimizer/Builder/Runtime/Character.h" #include "flang/Optimizer/Builder/Runtime/Command.h" @@ -88,452 +89,7 @@ return !isStaticallyAbsent(exv); } -constexpr auto asValue = fir::LowerIntrinsicArgAs::Value; -constexpr auto asAddr = fir::LowerIntrinsicArgAs::Addr; -constexpr auto asBox = fir::LowerIntrinsicArgAs::Box; -constexpr auto asInquired = fir::LowerIntrinsicArgAs::Inquired; -using I = IntrinsicLibrary; - -/// Flag to indicate that an intrinsic argument has to be handled as -/// being dynamically optional (e.g. special handling when actual -/// argument is an optional variable in the current scope). -static constexpr bool handleDynamicOptional = true; - -/// Table that drives the fir generation depending on the intrinsic or intrinsic -/// module procedure one to one mapping with Fortran arguments. If no mapping is -/// defined here for a generic intrinsic, genRuntimeCall will be called -/// to look for a match in the runtime a emit a call. Note that the argument -/// lowering rules for an intrinsic need to be provided only if at least one -/// argument must not be lowered by value. In which case, the lowering rules -/// should be provided for all the intrinsic arguments for completeness. -static constexpr IntrinsicHandler handlers[]{ - {"abort", &I::genAbort}, - {"abs", &I::genAbs}, - {"achar", &I::genChar}, - {"adjustl", - &I::genAdjustRtCall, - {{{"string", asAddr}}}, - /*isElemental=*/true}, - {"adjustr", - &I::genAdjustRtCall, - {{{"string", asAddr}}}, - /*isElemental=*/true}, - {"aimag", &I::genAimag}, - {"aint", &I::genAint}, - {"all", - &I::genAll, - {{{"mask", asAddr}, {"dim", asValue}}}, - /*isElemental=*/false}, - {"allocated", - &I::genAllocated, - {{{"array", asInquired}, {"scalar", asInquired}}}, - /*isElemental=*/false}, - {"anint", &I::genAnint}, - {"any", - &I::genAny, - {{{"mask", asAddr}, {"dim", asValue}}}, - /*isElemental=*/false}, - {"associated", - &I::genAssociated, - {{{"pointer", asInquired}, {"target", asInquired}}}, - /*isElemental=*/false}, - {"atand", &I::genAtand}, - {"bessel_jn", - &I::genBesselJn, - {{{"n1", asValue}, {"n2", asValue}, {"x", asValue}}}, - /*isElemental=*/false}, - {"bessel_yn", - &I::genBesselYn, - {{{"n1", asValue}, {"n2", asValue}, {"x", asValue}}}, - /*isElemental=*/false}, - {"bge", &I::genBitwiseCompare}, - {"bgt", &I::genBitwiseCompare}, - {"ble", &I::genBitwiseCompare}, - {"blt", &I::genBitwiseCompare}, - {"btest", &I::genBtest}, - {"c_associated_c_funptr", - &I::genCAssociatedCFunPtr, - {{{"c_ptr_1", asAddr}, {"c_ptr_2", asAddr, handleDynamicOptional}}}, - /*isElemental=*/false}, - {"c_associated_c_ptr", - &I::genCAssociatedCPtr, - {{{"c_ptr_1", asAddr}, {"c_ptr_2", asAddr, handleDynamicOptional}}}, - /*isElemental=*/false}, - {"c_f_pointer", - &I::genCFPointer, - {{{"cptr", asValue}, - {"fptr", asInquired}, - {"shape", asAddr, handleDynamicOptional}}}, - /*isElemental=*/false}, - {"c_funloc", &I::genCFunLoc, {{{"x", asBox}}}, /*isElemental=*/false}, - {"c_loc", &I::genCLoc, {{{"x", asBox}}}, /*isElemental=*/false}, - {"ceiling", &I::genCeiling}, - {"char", &I::genChar}, - {"cmplx", - &I::genCmplx, - {{{"x", asValue}, {"y", asValue, handleDynamicOptional}}}}, - {"command_argument_count", &I::genCommandArgumentCount}, - {"conjg", &I::genConjg}, - {"count", - &I::genCount, - {{{"mask", asAddr}, {"dim", asValue}, {"kind", asValue}}}, - /*isElemental=*/false}, - {"cpu_time", - &I::genCpuTime, - {{{"time", asAddr}}}, - /*isElemental=*/false}, - {"cshift", - &I::genCshift, - {{{"array", asAddr}, {"shift", asAddr}, {"dim", asValue}}}, - /*isElemental=*/false}, - {"date_and_time", - &I::genDateAndTime, - {{{"date", asAddr, handleDynamicOptional}, - {"time", asAddr, handleDynamicOptional}, - {"zone", asAddr, handleDynamicOptional}, - {"values", asBox, handleDynamicOptional}}}, - /*isElemental=*/false}, - {"dble", &I::genConversion}, - {"dim", &I::genDim}, - {"dot_product", - &I::genDotProduct, - {{{"vector_a", asBox}, {"vector_b", asBox}}}, - /*isElemental=*/false}, - {"dprod", &I::genDprod}, - {"dshiftl", &I::genDshiftl}, - {"dshiftr", &I::genDshiftr}, - {"eoshift", - &I::genEoshift, - {{{"array", asBox}, - {"shift", asAddr}, - {"boundary", asBox, handleDynamicOptional}, - {"dim", asValue}}}, - /*isElemental=*/false}, - {"exit", - &I::genExit, - {{{"status", asValue, handleDynamicOptional}}}, - /*isElemental=*/false}, - {"exponent", &I::genExponent}, - {"extends_type_of", - &I::genExtendsTypeOf, - {{{"a", asBox}, {"mold", asBox}}}, - /*isElemental=*/false}, - {"findloc", - &I::genFindloc, - {{{"array", asBox}, - {"value", asAddr}, - {"dim", asValue}, - {"mask", asBox, handleDynamicOptional}, - {"kind", asValue}, - {"back", asValue, handleDynamicOptional}}}, - /*isElemental=*/false}, - {"floor", &I::genFloor}, - {"fraction", &I::genFraction}, - {"get_command", - &I::genGetCommand, - {{{"command", asBox, handleDynamicOptional}, - {"length", asBox, handleDynamicOptional}, - {"status", asAddr, handleDynamicOptional}, - {"errmsg", asBox, handleDynamicOptional}}}, - /*isElemental=*/false}, - {"get_command_argument", - &I::genGetCommandArgument, - {{{"number", asValue}, - {"value", asBox, handleDynamicOptional}, - {"length", asBox, handleDynamicOptional}, - {"status", asAddr, handleDynamicOptional}, - {"errmsg", asBox, handleDynamicOptional}}}, - /*isElemental=*/false}, - {"get_environment_variable", - &I::genGetEnvironmentVariable, - {{{"name", asBox}, - {"value", asBox, handleDynamicOptional}, - {"length", asBox, handleDynamicOptional}, - {"status", asAddr, handleDynamicOptional}, - {"trim_name", asAddr, handleDynamicOptional}, - {"errmsg", asBox, handleDynamicOptional}}}, - /*isElemental=*/false}, - {"iachar", &I::genIchar}, - {"iall", - &I::genIall, - {{{"array", asBox}, - {"dim", asValue}, - {"mask", asBox, handleDynamicOptional}}}, - /*isElemental=*/false}, - {"iand", &I::genIand}, - {"iany", - &I::genIany, - {{{"array", asBox}, - {"dim", asValue}, - {"mask", asBox, handleDynamicOptional}}}, - /*isElemental=*/false}, - {"ibclr", &I::genIbclr}, - {"ibits", &I::genIbits}, - {"ibset", &I::genIbset}, - {"ichar", &I::genIchar}, - {"ieee_class_eq", &I::genIeeeTypeCompare}, - {"ieee_class_ne", &I::genIeeeTypeCompare}, - {"ieee_is_finite", &I::genIeeeIsFinite}, - {"ieee_is_nan", &I::genIsNan}, - {"ieee_is_normal", &I::genIeeeIsNormal}, - {"ieee_round_eq", &I::genIeeeTypeCompare}, - {"ieee_round_ne", &I::genIeeeTypeCompare}, - {"ieor", &I::genIeor}, - {"index", - &I::genIndex, - {{{"string", asAddr}, - {"substring", asAddr}, - {"back", asValue, handleDynamicOptional}, - {"kind", asValue}}}}, - {"ior", &I::genIor}, - {"iparity", - &I::genIparity, - {{{"array", asBox}, - {"dim", asValue}, - {"mask", asBox, handleDynamicOptional}}}, - /*isElemental=*/false}, - {"is_contiguous", - &I::genIsContiguous, - {{{"array", asBox}}}, - /*isElemental=*/false}, - {"is_iostat_end", &I::genIsIostatValue}, - {"is_iostat_eor", &I::genIsIostatValue}, - {"ishft", &I::genIshft}, - {"ishftc", &I::genIshftc}, - {"isnan", &I::genIsNan}, - {"lbound", - &I::genLbound, - {{{"array", asInquired}, {"dim", asValue}, {"kind", asValue}}}, - /*isElemental=*/false}, - {"leadz", &I::genLeadz}, - {"len", - &I::genLen, - {{{"string", asInquired}, {"kind", asValue}}}, - /*isElemental=*/false}, - {"len_trim", &I::genLenTrim}, - {"lge", &I::genCharacterCompare}, - {"lgt", &I::genCharacterCompare}, - {"lle", &I::genCharacterCompare}, - {"llt", &I::genCharacterCompare}, - {"loc", &I::genLoc, {{{"x", asBox}}}, /*isElemental=*/false}, - {"maskl", &I::genMask}, - {"maskr", &I::genMask}, - {"matmul", - &I::genMatmul, - {{{"matrix_a", asAddr}, {"matrix_b", asAddr}}}, - /*isElemental=*/false}, - {"matmul_transpose", - &I::genMatmulTranspose, - {{{"matrix_a", asAddr}, {"matrix_b", asAddr}}}, - /*isElemental=*/false}, - {"max", &I::genExtremum}, - {"maxloc", - &I::genMaxloc, - {{{"array", asBox}, - {"dim", asValue}, - {"mask", asBox, handleDynamicOptional}, - {"kind", asValue}, - {"back", asValue, handleDynamicOptional}}}, - /*isElemental=*/false}, - {"maxval", - &I::genMaxval, - {{{"array", asBox}, - {"dim", asValue}, - {"mask", asBox, handleDynamicOptional}}}, - /*isElemental=*/false}, - {"merge", &I::genMerge}, - {"merge_bits", &I::genMergeBits}, - {"min", &I::genExtremum}, - {"minloc", - &I::genMinloc, - {{{"array", asBox}, - {"dim", asValue}, - {"mask", asBox, handleDynamicOptional}, - {"kind", asValue}, - {"back", asValue, handleDynamicOptional}}}, - /*isElemental=*/false}, - {"minval", - &I::genMinval, - {{{"array", asBox}, - {"dim", asValue}, - {"mask", asBox, handleDynamicOptional}}}, - /*isElemental=*/false}, - {"mod", &I::genMod}, - {"modulo", &I::genModulo}, - {"move_alloc", - &I::genMoveAlloc, - {{{"from", asInquired}, - {"to", asInquired}, - {"status", asAddr, handleDynamicOptional}, - {"errMsg", asBox, handleDynamicOptional}}}, - /*isElemental=*/false}, - {"mvbits", - &I::genMvbits, - {{{"from", asValue}, - {"frompos", asValue}, - {"len", asValue}, - {"to", asAddr}, - {"topos", asValue}}}}, - {"nearest", &I::genNearest}, - {"nint", &I::genNint}, - {"norm2", - &I::genNorm2, - {{{"array", asBox}, {"dim", asValue}}}, - /*isElemental=*/false}, - {"not", &I::genNot}, - {"null", &I::genNull, {{{"mold", asInquired}}}, /*isElemental=*/false}, - {"pack", - &I::genPack, - {{{"array", asBox}, - {"mask", asBox}, - {"vector", asBox, handleDynamicOptional}}}, - /*isElemental=*/false}, - {"parity", - &I::genParity, - {{{"mask", asBox}, {"dim", asValue}}}, - /*isElemental=*/false}, - {"popcnt", &I::genPopcnt}, - {"poppar", &I::genPoppar}, - {"present", - &I::genPresent, - {{{"a", asInquired}}}, - /*isElemental=*/false}, - {"product", - &I::genProduct, - {{{"array", asBox}, - {"dim", asValue}, - {"mask", asBox, handleDynamicOptional}}}, - /*isElemental=*/false}, - {"random_init", - &I::genRandomInit, - {{{"repeatable", asValue}, {"image_distinct", asValue}}}, - /*isElemental=*/false}, - {"random_number", - &I::genRandomNumber, - {{{"harvest", asBox}}}, - /*isElemental=*/false}, - {"random_seed", - &I::genRandomSeed, - {{{"size", asBox, handleDynamicOptional}, - {"put", asBox, handleDynamicOptional}, - {"get", asBox, handleDynamicOptional}}}, - /*isElemental=*/false}, - {"reduce", - &I::genReduce, - {{{"array", asBox}, - {"operation", asAddr}, - {"dim", asValue}, - {"mask", asBox, handleDynamicOptional}, - {"identity", asValue}, - {"ordered", asValue}}}, - /*isElemental=*/false}, - {"repeat", - &I::genRepeat, - {{{"string", asAddr}, {"ncopies", asValue}}}, - /*isElemental=*/false}, - {"reshape", - &I::genReshape, - {{{"source", asBox}, - {"shape", asBox}, - {"pad", asBox, handleDynamicOptional}, - {"order", asBox, handleDynamicOptional}}}, - /*isElemental=*/false}, - {"rrspacing", &I::genRRSpacing}, - {"same_type_as", - &I::genSameTypeAs, - {{{"a", asBox}, {"b", asBox}}}, - /*isElemental=*/false}, - {"scale", - &I::genScale, - {{{"x", asValue}, {"i", asValue}}}, - /*isElemental=*/true}, - {"scan", - &I::genScan, - {{{"string", asAddr}, - {"set", asAddr}, - {"back", asValue, handleDynamicOptional}, - {"kind", asValue}}}, - /*isElemental=*/true}, - {"selected_int_kind", - &I::genSelectedIntKind, - {{{"scalar", asAddr}}}, - /*isElemental=*/false}, - {"selected_real_kind", - &I::genSelectedRealKind, - {{{"precision", asAddr, handleDynamicOptional}, - {"range", asAddr, handleDynamicOptional}, - {"radix", asAddr, handleDynamicOptional}}}, - /*isElemental=*/false}, - {"set_exponent", &I::genSetExponent}, - {"shifta", &I::genShiftA}, - {"shiftl", &I::genShift}, - {"shiftr", &I::genShift}, - {"sign", &I::genSign}, - {"size", - &I::genSize, - {{{"array", asBox}, - {"dim", asAddr, handleDynamicOptional}, - {"kind", asValue}}}, - /*isElemental=*/false}, - {"spacing", &I::genSpacing}, - {"spread", - &I::genSpread, - {{{"source", asBox}, {"dim", asValue}, {"ncopies", asValue}}}, - /*isElemental=*/false}, - {"storage_size", - &I::genStorageSize, - {{{"a", asInquired}, {"kind", asValue}}}, - /*isElemental=*/false}, - {"sum", - &I::genSum, - {{{"array", asBox}, - {"dim", asValue}, - {"mask", asBox, handleDynamicOptional}}}, - /*isElemental=*/false}, - {"system_clock", - &I::genSystemClock, - {{{"count", asAddr}, {"count_rate", asAddr}, {"count_max", asAddr}}}, - /*isElemental=*/false}, - {"trailz", &I::genTrailz}, - {"transfer", - &I::genTransfer, - {{{"source", asAddr}, {"mold", asAddr}, {"size", asValue}}}, - /*isElemental=*/false}, - {"transpose", - &I::genTranspose, - {{{"matrix", asAddr}}}, - /*isElemental=*/false}, - {"trim", &I::genTrim, {{{"string", asAddr}}}, /*isElemental=*/false}, - {"ubound", - &I::genUbound, - {{{"array", asBox}, {"dim", asValue}, {"kind", asValue}}}, - /*isElemental=*/false}, - {"unpack", - &I::genUnpack, - {{{"vector", asBox}, {"mask", asBox}, {"field", asBox}}}, - /*isElemental=*/false}, - {"verify", - &I::genVerify, - {{{"string", asAddr}, - {"set", asAddr}, - {"back", asValue, handleDynamicOptional}, - {"kind", asValue}}}, - /*isElemental=*/true}, -}; - -// PPC specific intrinsic handlers. -static constexpr IntrinsicHandler ppcHandlers[]{ - {"__ppc_mtfsf", - &I::genMtfsf, - {{{"mask", asValue}, {"r", asValue}}}, - /*isElemental=*/false}, - {"__ppc_mtfsfi", - &I::genMtfsf, - {{{"bf", asValue}, {"i", asValue}}}, - /*isElemental=*/false}, -}; - -static const IntrinsicHandler *findIntrinsicHandler(llvm::StringRef name) { +const IntrinsicHandler *findIntrinsicHandler(llvm::StringRef name) { auto compare = [](const IntrinsicHandler &handler, llvm::StringRef name) { return name.compare(handler.name) > 0; }; @@ -542,15 +98,6 @@ : nullptr; } -static const IntrinsicHandler *findPPCIntrinsicHandler(llvm::StringRef name) { - auto compare = [](const IntrinsicHandler &ppcHandler, llvm::StringRef name) { - return name.compare(ppcHandler.name) > 0; - }; - auto result = llvm::lower_bound(ppcHandlers, name, compare); - return result != std::end(ppcHandlers) && result->name == name ? result - : nullptr; -} - /// To make fir output more readable for debug, one can outline all intrinsic /// implementation in wrappers (overrides the IntrinsicHandler::outline flag). static llvm::cl::opt outlineAllIntrinsics( @@ -580,10 +127,10 @@ "dialect to lower complex operations"), llvm::cl::init(false)); -static mlir::Value genLibCall(fir::FirOpBuilder &builder, mlir::Location loc, - llvm::StringRef libFuncName, - mlir::FunctionType libFuncType, - llvm::ArrayRef args) { +mlir::Value genLibCall(fir::FirOpBuilder &builder, mlir::Location loc, + llvm::StringRef libFuncName, + mlir::FunctionType libFuncType, + llvm::ArrayRef args) { LLVM_DEBUG(llvm::dbgs() << "Generating '" << libFuncName << "' call with type "; libFuncType.dump(); llvm::dbgs() << "\n"); @@ -639,9 +186,11 @@ return libCall.getResult(0); } -static mlir::Value genLibSplitComplexArgsCall( - fir::FirOpBuilder &builder, mlir::Location loc, llvm::StringRef libFuncName, - mlir::FunctionType libFuncType, llvm::ArrayRef args) { +mlir::Value genLibSplitComplexArgsCall(fir::FirOpBuilder &builder, + mlir::Location loc, + llvm::StringRef libFuncName, + mlir::FunctionType libFuncType, + llvm::ArrayRef args) { assert(args.size() == 2 && "Incorrect #args to genLibSplitComplexArgsCall"); auto getSplitComplexArgsType = [&builder, &args]() -> mlir::FunctionType { @@ -688,10 +237,10 @@ } template -static mlir::Value genMathOp(fir::FirOpBuilder &builder, mlir::Location loc, - llvm::StringRef mathLibFuncName, - mlir::FunctionType mathLibFuncType, - llvm::ArrayRef args) { +mlir::Value genMathOp(fir::FirOpBuilder &builder, mlir::Location loc, + llvm::StringRef mathLibFuncName, + mlir::FunctionType mathLibFuncType, + llvm::ArrayRef args) { // TODO: we have to annotate the math operations with flags // that will allow to define FP accuracy/exception // behavior per operation, so that after early multi-module @@ -730,11 +279,10 @@ } template -static mlir::Value genComplexMathOp(fir::FirOpBuilder &builder, - mlir::Location loc, - llvm::StringRef mathLibFuncName, - mlir::FunctionType mathLibFuncType, - llvm::ArrayRef args) { +mlir::Value genComplexMathOp(fir::FirOpBuilder &builder, mlir::Location loc, + llvm::StringRef mathLibFuncName, + mlir::FunctionType mathLibFuncType, + llvm::ArrayRef args) { mlir::Value result; if (disableMlirComplex || (mathRuntimeVersion == preciseVersion && !mathLibFuncName.empty())) { @@ -772,329 +320,6 @@ return result; } -/// Mapping between mathematical intrinsic operations and MLIR operations -/// of some appropriate dialect (math, complex, etc.) or libm calls. -/// TODO: support remaining Fortran math intrinsics. -/// See https://gcc.gnu.org/onlinedocs/gcc-12.1.0/gfortran/\ -/// Intrinsic-Procedures.html for a reference. -static constexpr MathOperation mathOperations[] = { - {"abs", "fabsf", genFuncType, Ty::Real<4>>, - genMathOp}, - {"abs", "fabs", genFuncType, Ty::Real<8>>, - genMathOp}, - {"abs", "llvm.fabs.f128", genFuncType, Ty::Real<16>>, - genMathOp}, - {"abs", "cabsf", genFuncType, Ty::Complex<4>>, - genComplexMathOp}, - {"abs", "cabs", genFuncType, Ty::Complex<8>>, - genComplexMathOp}, - {"acos", "acosf", genFuncType, Ty::Real<4>>, genLibCall}, - {"acos", "acos", genFuncType, Ty::Real<8>>, genLibCall}, - {"acos", "cacosf", genFuncType, Ty::Complex<4>>, genLibCall}, - {"acos", "cacos", genFuncType, Ty::Complex<8>>, genLibCall}, - {"acosh", "acoshf", genFuncType, Ty::Real<4>>, genLibCall}, - {"acosh", "acosh", genFuncType, Ty::Real<8>>, genLibCall}, - {"acosh", "cacoshf", genFuncType, Ty::Complex<4>>, - genLibCall}, - {"acosh", "cacosh", genFuncType, Ty::Complex<8>>, - genLibCall}, - // llvm.trunc behaves the same way as libm's trunc. - {"aint", "llvm.trunc.f32", genFuncType, Ty::Real<4>>, - genLibCall}, - {"aint", "llvm.trunc.f64", genFuncType, Ty::Real<8>>, - genLibCall}, - {"aint", "llvm.trunc.f80", genFuncType, Ty::Real<10>>, - genLibCall}, - // llvm.round behaves the same way as libm's round. - {"anint", "llvm.round.f32", genFuncType, Ty::Real<4>>, - genMathOp}, - {"anint", "llvm.round.f64", genFuncType, Ty::Real<8>>, - genMathOp}, - {"anint", "llvm.round.f80", genFuncType, Ty::Real<10>>, - genMathOp}, - {"asin", "asinf", genFuncType, Ty::Real<4>>, genLibCall}, - {"asin", "asin", genFuncType, Ty::Real<8>>, genLibCall}, - {"asin", "casinf", genFuncType, Ty::Complex<4>>, genLibCall}, - {"asin", "casin", genFuncType, Ty::Complex<8>>, genLibCall}, - {"asinh", "asinhf", genFuncType, Ty::Real<4>>, genLibCall}, - {"asinh", "asinh", genFuncType, Ty::Real<8>>, genLibCall}, - {"asinh", "casinhf", genFuncType, Ty::Complex<4>>, - genLibCall}, - {"asinh", "casinh", genFuncType, Ty::Complex<8>>, - genLibCall}, - {"atan", "atanf", genFuncType, Ty::Real<4>>, - genMathOp}, - {"atan", "atan", genFuncType, Ty::Real<8>>, - genMathOp}, - {"atan", "catanf", genFuncType, Ty::Complex<4>>, genLibCall}, - {"atan", "catan", genFuncType, Ty::Complex<8>>, genLibCall}, - {"atan2", "atan2f", genFuncType, Ty::Real<4>, Ty::Real<4>>, - genMathOp}, - {"atan2", "atan2", genFuncType, Ty::Real<8>, Ty::Real<8>>, - genMathOp}, - {"atanh", "atanhf", genFuncType, Ty::Real<4>>, genLibCall}, - {"atanh", "atanh", genFuncType, Ty::Real<8>>, genLibCall}, - {"atanh", "catanhf", genFuncType, Ty::Complex<4>>, - genLibCall}, - {"atanh", "catanh", genFuncType, Ty::Complex<8>>, - genLibCall}, - {"bessel_j0", "j0f", genFuncType, Ty::Real<4>>, genLibCall}, - {"bessel_j0", "j0", genFuncType, Ty::Real<8>>, genLibCall}, - {"bessel_j1", "j1f", genFuncType, Ty::Real<4>>, genLibCall}, - {"bessel_j1", "j1", genFuncType, Ty::Real<8>>, genLibCall}, - {"bessel_jn", "jnf", genFuncType, Ty::Integer<4>, Ty::Real<4>>, - genLibCall}, - {"bessel_jn", "jn", genFuncType, Ty::Integer<4>, Ty::Real<8>>, - genLibCall}, - {"bessel_y0", "y0f", genFuncType, Ty::Real<4>>, genLibCall}, - {"bessel_y0", "y0", genFuncType, Ty::Real<8>>, genLibCall}, - {"bessel_y1", "y1f", genFuncType, Ty::Real<4>>, genLibCall}, - {"bessel_y1", "y1", genFuncType, Ty::Real<8>>, genLibCall}, - {"bessel_yn", "ynf", genFuncType, Ty::Integer<4>, Ty::Real<4>>, - genLibCall}, - {"bessel_yn", "yn", genFuncType, Ty::Integer<4>, Ty::Real<8>>, - genLibCall}, - // math::CeilOp returns a real, while Fortran CEILING returns integer. - {"ceil", "ceilf", genFuncType, Ty::Real<4>>, - genMathOp}, - {"ceil", "ceil", genFuncType, Ty::Real<8>>, - genMathOp}, - {"cos", "cosf", genFuncType, Ty::Real<4>>, - genMathOp}, - {"cos", "cos", genFuncType, Ty::Real<8>>, - genMathOp}, - {"cos", "ccosf", genFuncType, Ty::Complex<4>>, - genComplexMathOp}, - {"cos", "ccos", genFuncType, Ty::Complex<8>>, - genComplexMathOp}, - {"cosh", "coshf", genFuncType, Ty::Real<4>>, genLibCall}, - {"cosh", "cosh", genFuncType, Ty::Real<8>>, genLibCall}, - {"cosh", "ccoshf", genFuncType, Ty::Complex<4>>, genLibCall}, - {"cosh", "ccosh", genFuncType, Ty::Complex<8>>, genLibCall}, - {"divc", - {}, - genFuncType, Ty::Complex<2>, Ty::Complex<2>>, - genComplexMathOp}, - {"divc", - {}, - genFuncType, Ty::Complex<3>, Ty::Complex<3>>, - genComplexMathOp}, - {"divc", "__divsc3", - genFuncType, Ty::Complex<4>, Ty::Complex<4>>, - genLibSplitComplexArgsCall}, - {"divc", "__divdc3", - genFuncType, Ty::Complex<8>, Ty::Complex<8>>, - genLibSplitComplexArgsCall}, - {"divc", "__divxc3", - genFuncType, Ty::Complex<10>, Ty::Complex<10>>, - genLibSplitComplexArgsCall}, - {"divc", "__divtc3", - genFuncType, Ty::Complex<16>, Ty::Complex<16>>, - genLibSplitComplexArgsCall}, - {"erf", "erff", genFuncType, Ty::Real<4>>, - genMathOp}, - {"erf", "erf", genFuncType, Ty::Real<8>>, - genMathOp}, - {"erfc", "erfcf", genFuncType, Ty::Real<4>>, genLibCall}, - {"erfc", "erfc", genFuncType, Ty::Real<8>>, genLibCall}, - {"exp", "expf", genFuncType, Ty::Real<4>>, - genMathOp}, - {"exp", "exp", genFuncType, Ty::Real<8>>, - genMathOp}, - {"exp", "cexpf", genFuncType, Ty::Complex<4>>, - genComplexMathOp}, - {"exp", "cexp", genFuncType, Ty::Complex<8>>, - genComplexMathOp}, - // math::FloorOp returns a real, while Fortran FLOOR returns integer. - {"floor", "floorf", genFuncType, Ty::Real<4>>, - genMathOp}, - {"floor", "floor", genFuncType, Ty::Real<8>>, - genMathOp}, - {"fma", "llvm.fma.f32", - genFuncType, Ty::Real<4>, Ty::Real<4>, Ty::Real<4>>, - genMathOp}, - {"fma", "llvm.fma.f64", - genFuncType, Ty::Real<8>, Ty::Real<8>, Ty::Real<8>>, - genMathOp}, - {"gamma", "tgammaf", genFuncType, Ty::Real<4>>, genLibCall}, - {"gamma", "tgamma", genFuncType, Ty::Real<8>>, genLibCall}, - {"hypot", "hypotf", genFuncType, Ty::Real<4>, Ty::Real<4>>, - genLibCall}, - {"hypot", "hypot", genFuncType, Ty::Real<8>, Ty::Real<8>>, - genLibCall}, - {"log", "logf", genFuncType, Ty::Real<4>>, - genMathOp}, - {"log", "log", genFuncType, Ty::Real<8>>, - genMathOp}, - {"log", "clogf", genFuncType, Ty::Complex<4>>, - genComplexMathOp}, - {"log", "clog", genFuncType, Ty::Complex<8>>, - genComplexMathOp}, - {"log10", "log10f", genFuncType, Ty::Real<4>>, - genMathOp}, - {"log10", "log10", genFuncType, Ty::Real<8>>, - genMathOp}, - {"log_gamma", "lgammaf", genFuncType, Ty::Real<4>>, genLibCall}, - {"log_gamma", "lgamma", genFuncType, Ty::Real<8>>, genLibCall}, - // llvm.lround behaves the same way as libm's lround. - {"nint", "llvm.lround.i64.f64", genFuncType, Ty::Real<8>>, - genLibCall}, - {"nint", "llvm.lround.i64.f32", genFuncType, Ty::Real<4>>, - genLibCall}, - {"nint", "llvm.lround.i32.f64", genFuncType, Ty::Real<8>>, - genLibCall}, - {"nint", "llvm.lround.i32.f32", genFuncType, Ty::Real<4>>, - genLibCall}, - {"pow", - {}, - genFuncType, Ty::Integer<1>, Ty::Integer<1>>, - genMathOp}, - {"pow", - {}, - genFuncType, Ty::Integer<2>, Ty::Integer<2>>, - genMathOp}, - {"pow", - {}, - genFuncType, Ty::Integer<4>, Ty::Integer<4>>, - genMathOp}, - {"pow", - {}, - genFuncType, Ty::Integer<8>, Ty::Integer<8>>, - genMathOp}, - {"pow", "powf", genFuncType, Ty::Real<4>, Ty::Real<4>>, - genMathOp}, - {"pow", "pow", genFuncType, Ty::Real<8>, Ty::Real<8>>, - genMathOp}, - {"pow", "cpowf", - genFuncType, Ty::Complex<4>, Ty::Complex<4>>, - genComplexMathOp}, - {"pow", "cpow", genFuncType, Ty::Complex<8>, Ty::Complex<8>>, - genComplexMathOp}, - {"pow", RTNAME_STRING(FPow4i), - genFuncType, Ty::Real<4>, Ty::Integer<4>>, - genMathOp}, - {"pow", RTNAME_STRING(FPow8i), - genFuncType, Ty::Real<8>, Ty::Integer<4>>, - genMathOp}, - {"pow", RTNAME_STRING(FPow4k), - genFuncType, Ty::Real<4>, Ty::Integer<8>>, - genMathOp}, - {"pow", RTNAME_STRING(FPow8k), - genFuncType, Ty::Real<8>, Ty::Integer<8>>, - genMathOp}, - {"pow", RTNAME_STRING(cpowi), - genFuncType, Ty::Complex<4>, Ty::Integer<4>>, genLibCall}, - {"pow", RTNAME_STRING(zpowi), - genFuncType, Ty::Complex<8>, Ty::Integer<4>>, genLibCall}, - {"pow", RTNAME_STRING(cpowk), - genFuncType, Ty::Complex<4>, Ty::Integer<8>>, genLibCall}, - {"pow", RTNAME_STRING(zpowk), - genFuncType, Ty::Complex<8>, Ty::Integer<8>>, genLibCall}, - {"sign", "copysignf", genFuncType, Ty::Real<4>, Ty::Real<4>>, - genMathOp}, - {"sign", "copysign", genFuncType, Ty::Real<8>, Ty::Real<8>>, - genMathOp}, - {"sign", "copysignl", genFuncType, Ty::Real<10>, Ty::Real<10>>, - genMathOp}, - {"sign", "llvm.copysign.f128", - genFuncType, Ty::Real<16>, Ty::Real<16>>, - genMathOp}, - {"sin", "sinf", genFuncType, Ty::Real<4>>, - genMathOp}, - {"sin", "sin", genFuncType, Ty::Real<8>>, - genMathOp}, - {"sin", "csinf", genFuncType, Ty::Complex<4>>, - genComplexMathOp}, - {"sin", "csin", genFuncType, Ty::Complex<8>>, - genComplexMathOp}, - {"sinh", "sinhf", genFuncType, Ty::Real<4>>, genLibCall}, - {"sinh", "sinh", genFuncType, Ty::Real<8>>, genLibCall}, - {"sinh", "csinhf", genFuncType, Ty::Complex<4>>, genLibCall}, - {"sinh", "csinh", genFuncType, Ty::Complex<8>>, genLibCall}, - {"sqrt", "sqrtf", genFuncType, Ty::Real<4>>, - genMathOp}, - {"sqrt", "sqrt", genFuncType, Ty::Real<8>>, - genMathOp}, - {"sqrt", "csqrtf", genFuncType, Ty::Complex<4>>, - genComplexMathOp}, - {"sqrt", "csqrt", genFuncType, Ty::Complex<8>>, - genComplexMathOp}, - {"tan", "tanf", genFuncType, Ty::Real<4>>, - genMathOp}, - {"tan", "tan", genFuncType, Ty::Real<8>>, - genMathOp}, - {"tan", "ctanf", genFuncType, Ty::Complex<4>>, - genComplexMathOp}, - {"tan", "ctan", genFuncType, Ty::Complex<8>>, - genComplexMathOp}, - {"tanh", "tanhf", genFuncType, Ty::Real<4>>, - genMathOp}, - {"tanh", "tanh", genFuncType, Ty::Real<8>>, - genMathOp}, - {"tanh", "ctanhf", genFuncType, Ty::Complex<4>>, - genComplexMathOp}, - {"tanh", "ctanh", genFuncType, Ty::Complex<8>>, - genComplexMathOp}, -}; - -static constexpr MathOperation ppcMathOperations[] = { - // fcfi is just another name for fcfid, there is no llvm.ppc.fcfi. - {"__ppc_fcfi", "llvm.ppc.fcfid", genFuncType, Ty::Real<8>>, - genLibCall}, - {"__ppc_fcfid", "llvm.ppc.fcfid", genFuncType, Ty::Real<8>>, - genLibCall}, - {"__ppc_fcfud", "llvm.ppc.fcfud", genFuncType, Ty::Real<8>>, - genLibCall}, - {"__ppc_fctid", "llvm.ppc.fctid", genFuncType, Ty::Real<8>>, - genLibCall}, - {"__ppc_fctidz", "llvm.ppc.fctidz", genFuncType, Ty::Real<8>>, - genLibCall}, - {"__ppc_fctiw", "llvm.ppc.fctiw", genFuncType, Ty::Real<8>>, - genLibCall}, - {"__ppc_fctiwz", "llvm.ppc.fctiwz", genFuncType, Ty::Real<8>>, - genLibCall}, - {"__ppc_fctudz", "llvm.ppc.fctudz", genFuncType, Ty::Real<8>>, - genLibCall}, - {"__ppc_fctuwz", "llvm.ppc.fctuwz", genFuncType, Ty::Real<8>>, - genLibCall}, - {"__ppc_fmadd", "llvm.fma.f32", - genFuncType, Ty::Real<4>, Ty::Real<4>, Ty::Real<4>>, - genMathOp}, - {"__ppc_fmadd", "llvm.fma.f64", - genFuncType, Ty::Real<8>, Ty::Real<8>, Ty::Real<8>>, - genMathOp}, - {"__ppc_fmsub", "llvm.ppc.fmsubs", - genFuncType, Ty::Real<4>, Ty::Real<4>, Ty::Real<4>>, - genLibCall}, - {"__ppc_fmsub", "llvm.ppc.fmsub", - genFuncType, Ty::Real<8>, Ty::Real<8>, Ty::Real<8>>, - genLibCall}, - {"__ppc_fnabs", "llvm.ppc.fnabss", genFuncType, Ty::Real<4>>, - genLibCall}, - {"__ppc_fnabs", "llvm.ppc.fnabs", genFuncType, Ty::Real<8>>, - genLibCall}, - {"__ppc_fnmadd", "llvm.ppc.fnmadds", - genFuncType, Ty::Real<4>, Ty::Real<4>, Ty::Real<4>>, - genLibCall}, - {"__ppc_fnmadd", "llvm.ppc.fnmadd", - genFuncType, Ty::Real<8>, Ty::Real<8>, Ty::Real<8>>, - genLibCall}, - {"__ppc_fnmsub", "llvm.ppc.fnmsub.f32", - genFuncType, Ty::Real<4>, Ty::Real<4>, Ty::Real<4>>, - genLibCall}, - {"__ppc_fnmsub", "llvm.ppc.fnmsub.f64", - genFuncType, Ty::Real<8>, Ty::Real<8>, Ty::Real<8>>, - genLibCall}, - {"__ppc_fre", "llvm.ppc.fre", genFuncType, Ty::Real<8>>, - genLibCall}, - {"__ppc_fres", "llvm.ppc.fres", genFuncType, Ty::Real<4>>, - genLibCall}, - {"__ppc_frsqrte", "llvm.ppc.frsqrte", genFuncType, Ty::Real<8>>, - genLibCall}, - {"__ppc_frsqrtes", "llvm.ppc.frsqrtes", - genFuncType, Ty::Real<4>>, genLibCall}, -}; - // This helper class computes a "distance" between two function types. // The distance measures how many narrowing conversions of actual arguments // and result of "from" must be made in order to use "to" instead of "from". @@ -5212,33 +4437,6 @@ return result; } -//===----------------------------------------------------------------------===// -// PowerPC specific intrinsic handlers. -//===----------------------------------------------------------------------===// -template -void IntrinsicLibrary::genMtfsf(llvm::ArrayRef args) { - assert(args.size() == 2); - llvm::SmallVector scalarArgs; - for (const fir::ExtendedValue &arg : args) - if (arg.getUnboxed()) - scalarArgs.emplace_back(fir::getBase(arg)); - else - mlir::emitError(loc, "nonscalar intrinsic argument"); - - mlir::FunctionType libFuncType; - mlir::func::FuncOp funcOp; - if (isImm) { - libFuncType = genFuncType, Ty::Integer<4>>( - builder.getContext(), builder); - funcOp = builder.addNamedFunction(loc, "llvm.ppc.mtfsfi", libFuncType); - } else { - libFuncType = genFuncType, Ty::Real<8>>( - builder.getContext(), builder); - funcOp = builder.addNamedFunction(loc, "llvm.ppc.mtfsf", libFuncType); - } - builder.create(loc, funcOp, scalarArgs); -} - //===----------------------------------------------------------------------===// // Argument lowering rules interface for intrinsic or intrinsic module // procedure. diff --git a/flang/lib/Optimizer/Builder/PPCIntrinsicCall.cpp b/flang/lib/Optimizer/Builder/PPCIntrinsicCall.cpp new file mode 100644 --- /dev/null +++ b/flang/lib/Optimizer/Builder/PPCIntrinsicCall.cpp @@ -0,0 +1,59 @@ +//===-- PPCIntrinsicCall.cpp ----------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Helper routines for constructing the FIR dialect of MLIR for PowerPC +// intrinsics. Extensive use of MLIR interfaces and MLIR's coding style +// (https://mlir.llvm.org/getting_started/DeveloperGuide/) is used in this +// module. +// +//===----------------------------------------------------------------------===// + +#include "flang/Optimizer/Builder/PPCIntrinsicCall.h" +#include "flang/Optimizer/Builder/FIRBuilder.h" +#include "flang/Optimizer/Builder/IntrinsicCall.h" +#include "flang/Optimizer/Builder/MutableBox.h" + +namespace fir { + +const IntrinsicHandler *findPPCIntrinsicHandler(llvm::StringRef name) { + auto compare = [](const IntrinsicHandler &ppcHandler, llvm::StringRef name) { + return name.compare(ppcHandler.name) > 0; + }; + auto result = llvm::lower_bound(ppcHandlers, name, compare); + return result != std::end(ppcHandlers) && result->name == name ? result + : nullptr; +} + +//===----------------------------------------------------------------------===// +// PowerPC specific intrinsic handlers. +//===----------------------------------------------------------------------===// +template +void PPCIntrinsicLibrary::genMtfsf(llvm::ArrayRef args) { + assert(args.size() == 2); + llvm::SmallVector scalarArgs; + for (const fir::ExtendedValue &arg : args) + if (arg.getUnboxed()) + scalarArgs.emplace_back(fir::getBase(arg)); + else + mlir::emitError(loc, "nonscalar intrinsic argument"); + + mlir::FunctionType libFuncType; + mlir::func::FuncOp funcOp; + if (isImm) { + libFuncType = genFuncType, Ty::Integer<4>>( + builder.getContext(), builder); + funcOp = builder.addNamedFunction(loc, "llvm.ppc.mtfsfi", libFuncType); + } else { + libFuncType = genFuncType, Ty::Real<8>>( + builder.getContext(), builder); + funcOp = builder.addNamedFunction(loc, "llvm.ppc.mtfsf", libFuncType); + } + builder.create(loc, funcOp, scalarArgs); +} + +} // namespace fir