[flang-commits] [flang] e0df106 - [Flang] Move several definitions to IntrinsicCall header for code cleanliness and reusability

Paul Scoropan via flang-commits flang-commits at lists.llvm.org
Wed May 31 08:03:58 PDT 2023


Author: Paul Scoropan
Date: 2023-05-31T15:03:53Z
New Revision: e0df106818ccb90dc46c5296ed5ef2eda75564ff

URL: https://github.com/llvm/llvm-project/commit/e0df106818ccb90dc46c5296ed5ef2eda75564ff
DIFF: https://github.com/llvm/llvm-project/commit/e0df106818ccb90dc46c5296ed5ef2eda75564ff.diff

LOG: [Flang] Move several definitions to IntrinsicCall header for code cleanliness and reusability

In the future we intend to add support for many PowerPC-specific intrinsics that ideally will exist in a separate new PPCIntrinsicCall file. But first we need to move definitions to the IntrinsicCall header file to increase code cleanliness and readability and to make code reusable for when we add PPCIntrinsicCall.

Reviewed By: vzakhari

Differential Revision: https://reviews.llvm.org/D151715

Added: 
    

Modified: 
    flang/include/flang/Optimizer/Builder/IntrinsicCall.h
    flang/lib/Optimizer/Builder/IntrinsicCall.cpp

Removed: 
    


################################################################################
diff  --git a/flang/include/flang/Optimizer/Builder/IntrinsicCall.h b/flang/include/flang/Optimizer/Builder/IntrinsicCall.h
index 0d32976b6f606..af512382ea64b 100644
--- a/flang/include/flang/Optimizer/Builder/IntrinsicCall.h
+++ b/flang/include/flang/Optimizer/Builder/IntrinsicCall.h
@@ -10,6 +10,8 @@
 #define FORTRAN_LOWER_INTRINSICCALL_H
 
 #include "flang/Optimizer/Builder/FIRBuilder.h"
+#include "flang/Optimizer/Builder/Runtime/RTBuilder.h"
+#include "flang/Runtime/iostat.h"
 #include <optional>
 
 namespace fir {
@@ -27,6 +29,49 @@ genIntrinsicCall(fir::FirOpBuilder &, mlir::Location, llvm::StringRef name,
                  std::optional<mlir::Type> resultType,
                  llvm::ArrayRef<fir::ExtendedValue> args);
 
+/// Enums used to templatize and share lowering of MIN and MAX.
+enum class Extremum { Min, Max };
+
+// There are 
diff erent ways to deal with NaNs in MIN and MAX.
+// Known existing behaviors are listed below and can be selected for
+// f18 MIN/MAX implementation.
+enum class ExtremumBehavior {
+  // Note: the Signaling/quiet aspect of NaNs in the behaviors below are
+  // not described because there is no way to control/observe such aspect in
+  // MLIR/LLVM yet. The IEEE behaviors come with requirements regarding this
+  // aspect that are therefore currently not enforced. In the descriptions
+  // below, NaNs can be signaling or quite. Returned NaNs may be signaling
+  // if one of the input NaN was signaling but it cannot be guaranteed either.
+  // Existing compilers using an IEEE behavior (gfortran) also do not fulfill
+  // signaling/quiet requirements.
+  IeeeMinMaximumNumber,
+  // IEEE minimumNumber/maximumNumber behavior (754-2019, section 9.6):
+  // If one of the argument is and number and the other is NaN, return the
+  // number. If both arguements are NaN, return NaN.
+  // Compilers: gfortran.
+  IeeeMinMaximum,
+  // IEEE minimum/maximum behavior (754-2019, section 9.6):
+  // If one of the argument is NaN, return NaN.
+  MinMaxss,
+  // x86 minss/maxss behavior:
+  // If the second argument is a number and the other is NaN, return the number.
+  // In all other cases where at least one operand is NaN, return NaN.
+  // Compilers: xlf (only for MAX), ifort, pgfortran -nollvm, and nagfor.
+  PgfortranLlvm,
+  // "Opposite of" x86 minss/maxss behavior:
+  // If the first argument is a number and the other is NaN, return the
+  // number.
+  // In all other cases where at least one operand is NaN, return NaN.
+  // Compilers: xlf (only for MIN), and pgfortran (with llvm).
+  IeeeMinMaxNum
+  // IEEE minNum/maxNum behavior (754-2008, section 5.3.1):
+  // TODO: Not implemented.
+  // It is the only behavior where the signaling/quiet aspect of a NaN argument
+  // impacts if the result should be NaN or the argument that is a number.
+  // LLVM/MLIR do not provide ways to observe this aspect, so it is not
+  // possible to implement it without some target dependent runtime.
+};
+
 /// Enum specifying how intrinsic argument evaluate::Expr should be
 /// lowered to fir::ExtendedValue to be passed to genIntrinsicCall.
 enum class LowerIntrinsicArgAs {
@@ -63,6 +108,361 @@ struct ArgLoweringRule {
 /// an intrinsic.
 struct IntrinsicArgumentLoweringRules;
 
+// TODO error handling -> return a code or directly emit messages ?
+struct IntrinsicLibrary {
+
+  // Constructors.
+  explicit IntrinsicLibrary(fir::FirOpBuilder &builder, mlir::Location loc)
+      : builder{builder}, loc{loc} {}
+  IntrinsicLibrary() = delete;
+  IntrinsicLibrary(const IntrinsicLibrary &) = delete;
+
+  /// Generate FIR for call to Fortran intrinsic \p name with arguments \p arg
+  /// and expected result type \p resultType. Return the result and a boolean
+  /// that, if true, indicates that the result must be freed after use.
+  std::pair<fir::ExtendedValue, bool>
+  genIntrinsicCall(llvm::StringRef name, std::optional<mlir::Type> resultType,
+                   llvm::ArrayRef<fir::ExtendedValue> arg);
+
+  /// Search a runtime function that is associated to the generic intrinsic name
+  /// and whose signature matches the intrinsic arguments and result types.
+  /// If no such runtime function is found but a runtime function associated
+  /// with the Fortran generic exists and has the same number of arguments,
+  /// conversions will be inserted before and/or after the call. This is to
+  /// mainly to allow 16 bits float support even-though little or no math
+  /// runtime is currently available for it.
+  mlir::Value genRuntimeCall(llvm::StringRef name, mlir::Type,
+                             llvm::ArrayRef<mlir::Value>);
+
+  using RuntimeCallGenerator = std::function<mlir::Value(
+      fir::FirOpBuilder &, mlir::Location, llvm::ArrayRef<mlir::Value>)>;
+  RuntimeCallGenerator
+  getRuntimeCallGenerator(llvm::StringRef name,
+                          mlir::FunctionType soughtFuncType);
+
+  void genAbort(llvm::ArrayRef<fir::ExtendedValue>);
+  /// Lowering for the ABS intrinsic. The ABS intrinsic expects one argument in
+  /// the llvm::ArrayRef. The ABS intrinsic is lowered into MLIR/FIR operation
+  /// if the argument is an integer, into llvm intrinsics if the argument is
+  /// real and to the `hypot` math routine if the argument is of complex type.
+  mlir::Value genAbs(mlir::Type, llvm::ArrayRef<mlir::Value>);
+  template <void (*CallRuntime)(fir::FirOpBuilder &, mlir::Location loc,
+                                mlir::Value, mlir::Value)>
+  fir::ExtendedValue genAdjustRtCall(mlir::Type,
+                                     llvm::ArrayRef<fir::ExtendedValue>);
+  mlir::Value genAimag(mlir::Type, llvm::ArrayRef<mlir::Value>);
+  mlir::Value genAint(mlir::Type, llvm::ArrayRef<mlir::Value>);
+  fir::ExtendedValue genAll(mlir::Type, llvm::ArrayRef<fir::ExtendedValue>);
+  fir::ExtendedValue genAllocated(mlir::Type,
+                                  llvm::ArrayRef<fir::ExtendedValue>);
+  mlir::Value genAnint(mlir::Type, llvm::ArrayRef<mlir::Value>);
+  fir::ExtendedValue genAny(mlir::Type, llvm::ArrayRef<fir::ExtendedValue>);
+  mlir::Value genAtand(mlir::Type, llvm::ArrayRef<mlir::Value>);
+  fir::ExtendedValue
+      genCommandArgumentCount(mlir::Type, llvm::ArrayRef<fir::ExtendedValue>);
+  fir::ExtendedValue genAssociated(mlir::Type,
+                                   llvm::ArrayRef<fir::ExtendedValue>);
+  fir::ExtendedValue genBesselJn(mlir::Type,
+                                 llvm::ArrayRef<fir::ExtendedValue>);
+  fir::ExtendedValue genBesselYn(mlir::Type,
+                                 llvm::ArrayRef<fir::ExtendedValue>);
+  /// Lower a bitwise comparison intrinsic using the given comparator.
+  template <mlir::arith::CmpIPredicate pred>
+  mlir::Value genBitwiseCompare(mlir::Type resultType,
+                                llvm::ArrayRef<mlir::Value> args);
+
+  mlir::Value genBtest(mlir::Type, llvm::ArrayRef<mlir::Value>);
+  mlir::Value genCeiling(mlir::Type, llvm::ArrayRef<mlir::Value>);
+  fir::ExtendedValue genChar(mlir::Type, llvm::ArrayRef<fir::ExtendedValue>);
+  template <mlir::arith::CmpIPredicate pred>
+  fir::ExtendedValue genCharacterCompare(mlir::Type,
+                                         llvm::ArrayRef<fir::ExtendedValue>);
+  mlir::Value genCmplx(mlir::Type, llvm::ArrayRef<mlir::Value>);
+  mlir::Value genConjg(mlir::Type, llvm::ArrayRef<mlir::Value>);
+  fir::ExtendedValue genCount(mlir::Type, llvm::ArrayRef<fir::ExtendedValue>);
+  void genCpuTime(llvm::ArrayRef<fir::ExtendedValue>);
+  fir::ExtendedValue genCshift(mlir::Type, llvm::ArrayRef<fir::ExtendedValue>);
+  fir::ExtendedValue genCAssociatedCFunPtr(mlir::Type,
+                                           llvm::ArrayRef<fir::ExtendedValue>);
+  fir::ExtendedValue genCAssociatedCPtr(mlir::Type,
+                                        llvm::ArrayRef<fir::ExtendedValue>);
+  void genCFPointer(llvm::ArrayRef<fir::ExtendedValue>);
+  fir::ExtendedValue genCFunLoc(mlir::Type, llvm::ArrayRef<fir::ExtendedValue>);
+  fir::ExtendedValue genCLoc(mlir::Type, llvm::ArrayRef<fir::ExtendedValue>);
+  void genDateAndTime(llvm::ArrayRef<fir::ExtendedValue>);
+  mlir::Value genDim(mlir::Type, llvm::ArrayRef<mlir::Value>);
+  fir::ExtendedValue genDotProduct(mlir::Type,
+                                   llvm::ArrayRef<fir::ExtendedValue>);
+  mlir::Value genDprod(mlir::Type, llvm::ArrayRef<mlir::Value>);
+  mlir::Value genDshiftl(mlir::Type, llvm::ArrayRef<mlir::Value>);
+  mlir::Value genDshiftr(mlir::Type, llvm::ArrayRef<mlir::Value>);
+  fir::ExtendedValue genEoshift(mlir::Type, llvm::ArrayRef<fir::ExtendedValue>);
+  void genExit(llvm::ArrayRef<fir::ExtendedValue>);
+  mlir::Value genExponent(mlir::Type, llvm::ArrayRef<mlir::Value>);
+  fir::ExtendedValue genExtendsTypeOf(mlir::Type,
+                                      llvm::ArrayRef<fir::ExtendedValue>);
+  template <Extremum, ExtremumBehavior>
+  mlir::Value genExtremum(mlir::Type, llvm::ArrayRef<mlir::Value>);
+  mlir::Value genFloor(mlir::Type, llvm::ArrayRef<mlir::Value>);
+  mlir::Value genFraction(mlir::Type resultType,
+                          mlir::ArrayRef<mlir::Value> args);
+  void genGetCommand(mlir::ArrayRef<fir::ExtendedValue> args);
+  void genGetCommandArgument(mlir::ArrayRef<fir::ExtendedValue> args);
+  void genGetEnvironmentVariable(llvm::ArrayRef<fir::ExtendedValue>);
+  fir::ExtendedValue genIall(mlir::Type, llvm::ArrayRef<fir::ExtendedValue>);
+  /// Lowering for the IAND intrinsic. The IAND intrinsic expects two arguments
+  /// in the llvm::ArrayRef.
+  mlir::Value genIand(mlir::Type, llvm::ArrayRef<mlir::Value>);
+  fir::ExtendedValue genIany(mlir::Type, llvm::ArrayRef<fir::ExtendedValue>);
+  mlir::Value genIbclr(mlir::Type, llvm::ArrayRef<mlir::Value>);
+  mlir::Value genIbits(mlir::Type, llvm::ArrayRef<mlir::Value>);
+  mlir::Value genIbset(mlir::Type, llvm::ArrayRef<mlir::Value>);
+  fir::ExtendedValue genIchar(mlir::Type, llvm::ArrayRef<fir::ExtendedValue>);
+  fir::ExtendedValue genFindloc(mlir::Type, llvm::ArrayRef<fir::ExtendedValue>);
+  mlir::Value genIeeeIsFinite(mlir::Type, llvm::ArrayRef<mlir::Value>);
+  mlir::Value genIeeeIsNormal(mlir::Type, llvm::ArrayRef<mlir::Value>);
+  template <mlir::arith::CmpIPredicate pred>
+  fir::ExtendedValue genIeeeTypeCompare(mlir::Type,
+                                        llvm::ArrayRef<fir::ExtendedValue>);
+  mlir::Value genIeor(mlir::Type, llvm::ArrayRef<mlir::Value>);
+  fir::ExtendedValue genIndex(mlir::Type, llvm::ArrayRef<fir::ExtendedValue>);
+  mlir::Value genIor(mlir::Type, llvm::ArrayRef<mlir::Value>);
+  fir::ExtendedValue genIparity(mlir::Type, llvm::ArrayRef<fir::ExtendedValue>);
+  fir::ExtendedValue genIsContiguous(mlir::Type,
+                                     llvm::ArrayRef<fir::ExtendedValue>);
+  template <Fortran::runtime::io::Iostat value>
+  mlir::Value genIsIostatValue(mlir::Type, llvm::ArrayRef<mlir::Value>);
+  mlir::Value genIsNan(mlir::Type, llvm::ArrayRef<mlir::Value>);
+  mlir::Value genIsFPClass(mlir::Type, llvm::ArrayRef<mlir::Value>,
+                           int fpclass);
+  mlir::Value genIshft(mlir::Type, llvm::ArrayRef<mlir::Value>);
+  mlir::Value genIshftc(mlir::Type, llvm::ArrayRef<mlir::Value>);
+  fir::ExtendedValue genLbound(mlir::Type, llvm::ArrayRef<fir::ExtendedValue>);
+  mlir::Value genLeadz(mlir::Type, llvm::ArrayRef<mlir::Value>);
+  fir::ExtendedValue genLen(mlir::Type, llvm::ArrayRef<fir::ExtendedValue>);
+  fir::ExtendedValue genLenTrim(mlir::Type, llvm::ArrayRef<fir::ExtendedValue>);
+  fir::ExtendedValue genLoc(mlir::Type, llvm::ArrayRef<fir::ExtendedValue>);
+  template <typename Shift>
+  mlir::Value genMask(mlir::Type, llvm::ArrayRef<mlir::Value>);
+  fir::ExtendedValue genMatmul(mlir::Type, llvm::ArrayRef<fir::ExtendedValue>);
+  fir::ExtendedValue genMatmulTranspose(mlir::Type,
+                                        llvm::ArrayRef<fir::ExtendedValue>);
+  fir::ExtendedValue genMaxloc(mlir::Type, llvm::ArrayRef<fir::ExtendedValue>);
+  fir::ExtendedValue genMaxval(mlir::Type, llvm::ArrayRef<fir::ExtendedValue>);
+  fir::ExtendedValue genMerge(mlir::Type, llvm::ArrayRef<fir::ExtendedValue>);
+  mlir::Value genMergeBits(mlir::Type, llvm::ArrayRef<mlir::Value>);
+  fir::ExtendedValue genMinloc(mlir::Type, llvm::ArrayRef<fir::ExtendedValue>);
+  fir::ExtendedValue genMinval(mlir::Type, llvm::ArrayRef<fir::ExtendedValue>);
+  mlir::Value genMod(mlir::Type, llvm::ArrayRef<mlir::Value>);
+  mlir::Value genModulo(mlir::Type, llvm::ArrayRef<mlir::Value>);
+  void genMoveAlloc(llvm::ArrayRef<fir::ExtendedValue>);
+  void genMvbits(llvm::ArrayRef<fir::ExtendedValue>);
+  mlir::Value genNearest(mlir::Type, llvm::ArrayRef<mlir::Value>);
+  mlir::Value genNint(mlir::Type, llvm::ArrayRef<mlir::Value>);
+  fir::ExtendedValue genNorm2(mlir::Type, llvm::ArrayRef<fir::ExtendedValue>);
+  mlir::Value genNot(mlir::Type, llvm::ArrayRef<mlir::Value>);
+  fir::ExtendedValue genNull(mlir::Type, llvm::ArrayRef<fir::ExtendedValue>);
+  fir::ExtendedValue genPack(mlir::Type, llvm::ArrayRef<fir::ExtendedValue>);
+  fir::ExtendedValue genParity(mlir::Type, llvm::ArrayRef<fir::ExtendedValue>);
+  mlir::Value genPopcnt(mlir::Type, llvm::ArrayRef<mlir::Value>);
+  mlir::Value genPoppar(mlir::Type, llvm::ArrayRef<mlir::Value>);
+  fir::ExtendedValue genPresent(mlir::Type, llvm::ArrayRef<fir::ExtendedValue>);
+  fir::ExtendedValue genProduct(mlir::Type, llvm::ArrayRef<fir::ExtendedValue>);
+  void genRandomInit(llvm::ArrayRef<fir::ExtendedValue>);
+  void genRandomNumber(llvm::ArrayRef<fir::ExtendedValue>);
+  void genRandomSeed(llvm::ArrayRef<fir::ExtendedValue>);
+  fir::ExtendedValue genReduce(mlir::Type, llvm::ArrayRef<fir::ExtendedValue>);
+  fir::ExtendedValue genRepeat(mlir::Type, llvm::ArrayRef<fir::ExtendedValue>);
+  fir::ExtendedValue genReshape(mlir::Type, llvm::ArrayRef<fir::ExtendedValue>);
+  mlir::Value genRRSpacing(mlir::Type resultType,
+                           llvm::ArrayRef<mlir::Value> args);
+  fir::ExtendedValue genSameTypeAs(mlir::Type,
+                                   llvm::ArrayRef<fir::ExtendedValue>);
+  mlir::Value genScale(mlir::Type, llvm::ArrayRef<mlir::Value>);
+  fir::ExtendedValue genScan(mlir::Type, llvm::ArrayRef<fir::ExtendedValue>);
+  mlir::Value genSelectedIntKind(mlir::Type, llvm::ArrayRef<mlir::Value>);
+  mlir::Value genSelectedRealKind(mlir::Type, llvm::ArrayRef<mlir::Value>);
+  mlir::Value genSetExponent(mlir::Type resultType,
+                             llvm::ArrayRef<mlir::Value> args);
+  template <typename Shift>
+  mlir::Value genShift(mlir::Type resultType, llvm::ArrayRef<mlir::Value>);
+  mlir::Value genShiftA(mlir::Type resultType, llvm::ArrayRef<mlir::Value>);
+  mlir::Value genSign(mlir::Type, llvm::ArrayRef<mlir::Value>);
+  fir::ExtendedValue genSize(mlir::Type, llvm::ArrayRef<fir::ExtendedValue>);
+  mlir::Value genSpacing(mlir::Type resultType,
+                         llvm::ArrayRef<mlir::Value> args);
+  fir::ExtendedValue genSpread(mlir::Type, llvm::ArrayRef<fir::ExtendedValue>);
+  fir::ExtendedValue genStorageSize(mlir::Type,
+                                    llvm::ArrayRef<fir::ExtendedValue>);
+  fir::ExtendedValue genSum(mlir::Type, llvm::ArrayRef<fir::ExtendedValue>);
+  void genSystemClock(llvm::ArrayRef<fir::ExtendedValue>);
+  mlir::Value genTrailz(mlir::Type, llvm::ArrayRef<mlir::Value>);
+  fir::ExtendedValue genTransfer(mlir::Type,
+                                 llvm::ArrayRef<fir::ExtendedValue>);
+  fir::ExtendedValue genTranspose(mlir::Type,
+                                  llvm::ArrayRef<fir::ExtendedValue>);
+  fir::ExtendedValue genTrim(mlir::Type, llvm::ArrayRef<fir::ExtendedValue>);
+  fir::ExtendedValue genUbound(mlir::Type, llvm::ArrayRef<fir::ExtendedValue>);
+  fir::ExtendedValue genUnpack(mlir::Type, llvm::ArrayRef<fir::ExtendedValue>);
+  fir::ExtendedValue genVerify(mlir::Type, llvm::ArrayRef<fir::ExtendedValue>);
+  /// Implement all conversion functions like DBLE, the first argument is
+  /// the value to convert. There may be an additional KIND arguments that
+  /// is ignored because this is already reflected in the result type.
+  mlir::Value genConversion(mlir::Type, llvm::ArrayRef<mlir::Value>);
+
+  // PPC intrinsic handlers.
+  template <bool isImm>
+  void genMtfsf(llvm::ArrayRef<fir::ExtendedValue>);
+
+  /// 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.
+  ///  - "FC funcChar" is a callback to generate the character runtime call.
+  /// Helper for MinLoc/MaxLoc.
+  template <typename FN, typename FD>
+  fir::ExtendedValue genExtremumloc(FN func, FD funcDim, llvm::StringRef errMsg,
+                                    mlir::Type,
+                                    llvm::ArrayRef<fir::ExtendedValue>);
+  template <typename FN, typename FD, typename FC>
+  /// Helper for MinVal/MaxVal.
+  fir::ExtendedValue genExtremumVal(FN func, FD funcDim, FC funcChar,
+                                    llvm::StringRef errMsg,
+                                    mlir::Type resultType,
+                                    llvm::ArrayRef<fir::ExtendedValue> args);
+  /// Process calls to Product, Sum, IAll, IAny, IParity intrinsic functions
+  template <typename FN, typename FD>
+  fir::ExtendedValue genReduction(FN func, FD funcDim, llvm::StringRef errMsg,
+                                  mlir::Type resultType,
+                                  llvm::ArrayRef<fir::ExtendedValue> args);
+
+  /// Define the 
diff erent FIR generators that can be mapped to intrinsic to
+  /// generate the related code.
+  using ElementalGenerator = decltype(&IntrinsicLibrary::genAbs);
+  using ExtendedGenerator = decltype(&IntrinsicLibrary::genLenTrim);
+  using SubroutineGenerator = decltype(&IntrinsicLibrary::genDateAndTime);
+  using Generator =
+      std::variant<ElementalGenerator, ExtendedGenerator, SubroutineGenerator>;
+
+  /// All generators can be outlined. This will build a function named
+  /// "fir."+ <generic name> + "." + <result type code> and generate the
+  /// intrinsic implementation inside instead of at the intrinsic call sites.
+  /// This can be used to keep the FIR more readable. Only one function will
+  /// be generated for all the similar calls in a program.
+  /// If the Generator is nullptr, the wrapper uses genRuntimeCall.
+  template <typename GeneratorType>
+  mlir::Value outlineInWrapper(GeneratorType, llvm::StringRef name,
+                               mlir::Type resultType,
+                               llvm::ArrayRef<mlir::Value> args);
+  template <typename GeneratorType>
+  fir::ExtendedValue
+  outlineInExtendedWrapper(GeneratorType, llvm::StringRef name,
+                           std::optional<mlir::Type> resultType,
+                           llvm::ArrayRef<fir::ExtendedValue> args);
+
+  template <typename GeneratorType>
+  mlir::func::FuncOp getWrapper(GeneratorType, llvm::StringRef name,
+                                mlir::FunctionType,
+                                bool loadRefArguments = false);
+
+  /// Generate calls to ElementalGenerator, handling the elemental aspects
+  template <typename GeneratorType>
+  fir::ExtendedValue
+  genElementalCall(GeneratorType, llvm::StringRef name, mlir::Type resultType,
+                   llvm::ArrayRef<fir::ExtendedValue> args, bool outline);
+
+  /// Helper to invoke code generator for the intrinsics given arguments.
+  mlir::Value invokeGenerator(ElementalGenerator generator,
+                              mlir::Type resultType,
+                              llvm::ArrayRef<mlir::Value> args);
+  mlir::Value invokeGenerator(RuntimeCallGenerator generator,
+                              mlir::Type resultType,
+                              llvm::ArrayRef<mlir::Value> args);
+  mlir::Value invokeGenerator(ExtendedGenerator generator,
+                              mlir::Type resultType,
+                              llvm::ArrayRef<mlir::Value> args);
+  mlir::Value invokeGenerator(SubroutineGenerator generator,
+                              llvm::ArrayRef<mlir::Value> args);
+
+  /// Get pointer to unrestricted intrinsic. Generate the related unrestricted
+  /// intrinsic if it is not defined yet.
+  mlir::SymbolRefAttr
+  getUnrestrictedIntrinsicSymbolRefAttr(llvm::StringRef name,
+                                        mlir::FunctionType signature);
+
+  /// Helper function for generating code clean-up for result descriptors
+  fir::ExtendedValue readAndAddCleanUp(fir::MutableBoxValue resultMutableBox,
+                                       mlir::Type resultType,
+                                       llvm::StringRef errMsg);
+
+  void setResultMustBeFreed() { resultMustBeFreed = true; }
+
+  fir::FirOpBuilder &builder;
+  mlir::Location loc;
+  bool resultMustBeFreed = false;
+};
+
+struct IntrinsicDummyArgument {
+  const char *name = nullptr;
+  fir::LowerIntrinsicArgAs lowerAs = fir::LowerIntrinsicArgAs::Value;
+  bool handleDynamicOptional = false;
+};
+
+/// This is shared by intrinsics and intrinsic module procedures.
+struct IntrinsicArgumentLoweringRules {
+  /// There is no more than 7 non repeated arguments in Fortran intrinsics.
+  IntrinsicDummyArgument args[7];
+  constexpr bool hasDefaultRules() const { return args[0].name == nullptr; }
+};
+
+/// Structure describing what needs to be done to lower intrinsic or intrinsic
+/// module procedure "name".
+struct IntrinsicHandler {
+  const char *name;
+  IntrinsicLibrary::Generator generator;
+  // The following may be omitted in the table below.
+  fir::IntrinsicArgumentLoweringRules argLoweringRules = {};
+  bool isElemental = true;
+  /// Code heavy intrinsic can be outlined to make FIR
+  /// more readable.
+  bool outline = false;
+};
+
+struct RuntimeFunction {
+  // llvm::StringRef comparison operator are not constexpr, so use string_view.
+  using Key = std::string_view;
+  // Needed for implicit compare with keys.
+  constexpr operator Key() const { return key; }
+  Key key; // intrinsic name
+
+  // Name of a runtime function that implements the operation.
+  llvm::StringRef symbol;
+  fir::runtime::FuncTypeBuilderFunc typeGenerator;
+};
+
+/// Callback type for generating lowering for a math operation.
+using MathGeneratorTy = mlir::Value (*)(fir::FirOpBuilder &, mlir::Location,
+                                        llvm::StringRef, mlir::FunctionType,
+                                        llvm::ArrayRef<mlir::Value>);
+
+struct MathOperation {
+  // llvm::StringRef comparison operator are not constexpr, so use string_view.
+  using Key = std::string_view;
+  // Needed for implicit compare with keys.
+  constexpr operator Key() const { return key; }
+  // Intrinsic name.
+  Key key;
+
+  // Name of a runtime function that implements the operation.
+  llvm::StringRef runtimeFunc;
+  fir::runtime::FuncTypeBuilderFunc typeGenerator;
+
+  // A callback to generate FIR for the intrinsic defined by 'key'.
+  // A callback may generate either dedicated MLIR operation(s) or
+  // a function call to a runtime function with name defined by
+  // 'runtimeFunc'.
+  MathGeneratorTy funcGenerator;
+};
+
 /// 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/lib/Optimizer/Builder/IntrinsicCall.cpp b/flang/lib/Optimizer/Builder/IntrinsicCall.cpp
index 2ee6f404ceef1..b368e6987e284 100644
--- a/flang/lib/Optimizer/Builder/IntrinsicCall.cpp
+++ b/flang/lib/Optimizer/Builder/IntrinsicCall.cpp
@@ -61,52 +61,9 @@
 /// a call is generated for it. LLVM intrinsics are handled as a math
 /// runtime library here.
 
-/// Enums used to templatize and share lowering of MIN and MAX.
-enum class Extremum { Min, Max };
-
-// There are 
diff erent ways to deal with NaNs in MIN and MAX.
-// Known existing behaviors are listed below and can be selected for
-// f18 MIN/MAX implementation.
-enum class ExtremumBehavior {
-  // Note: the Signaling/quiet aspect of NaNs in the behaviors below are
-  // not described because there is no way to control/observe such aspect in
-  // MLIR/LLVM yet. The IEEE behaviors come with requirements regarding this
-  // aspect that are therefore currently not enforced. In the descriptions
-  // below, NaNs can be signaling or quite. Returned NaNs may be signaling
-  // if one of the input NaN was signaling but it cannot be guaranteed either.
-  // Existing compilers using an IEEE behavior (gfortran) also do not fulfill
-  // signaling/quiet requirements.
-  IeeeMinMaximumNumber,
-  // IEEE minimumNumber/maximumNumber behavior (754-2019, section 9.6):
-  // If one of the argument is and number and the other is NaN, return the
-  // number. If both arguements are NaN, return NaN.
-  // Compilers: gfortran.
-  IeeeMinMaximum,
-  // IEEE minimum/maximum behavior (754-2019, section 9.6):
-  // If one of the argument is NaN, return NaN.
-  MinMaxss,
-  // x86 minss/maxss behavior:
-  // If the second argument is a number and the other is NaN, return the number.
-  // In all other cases where at least one operand is NaN, return NaN.
-  // Compilers: xlf (only for MAX), ifort, pgfortran -nollvm, and nagfor.
-  PgfortranLlvm,
-  // "Opposite of" x86 minss/maxss behavior:
-  // If the first argument is a number and the other is NaN, return the
-  // number.
-  // In all other cases where at least one operand is NaN, return NaN.
-  // Compilers: xlf (only for MIN), and pgfortran (with llvm).
-  IeeeMinMaxNum
-  // IEEE minNum/maxNum behavior (754-2008, section 5.3.1):
-  // TODO: Not implemented.
-  // It is the only behavior where the signaling/quiet aspect of a NaN argument
-  // impacts if the result should be NaN or the argument that is a number.
-  // LLVM/MLIR do not provide ways to observe this aspect, so it is not
-  // possible to implement it without some target dependent runtime.
-};
+namespace fir {
 
-fir::ExtendedValue fir::getAbsentIntrinsicArgument() {
-  return fir::UnboxedValue{};
-}
+fir::ExtendedValue getAbsentIntrinsicArgument() { return fir::UnboxedValue{}; }
 
 /// Test if an ExtendedValue is absent. This is used to test if an intrinsic
 /// argument are absent at compile time.
@@ -131,326 +88,6 @@ static bool isStaticallyPresent(const fir::ExtendedValue &exv) {
   return !isStaticallyAbsent(exv);
 }
 
-// TODO error handling -> return a code or directly emit messages ?
-struct IntrinsicLibrary {
-
-  // Constructors.
-  explicit IntrinsicLibrary(fir::FirOpBuilder &builder, mlir::Location loc)
-      : builder{builder}, loc{loc} {}
-  IntrinsicLibrary() = delete;
-  IntrinsicLibrary(const IntrinsicLibrary &) = delete;
-
-  /// Generate FIR for call to Fortran intrinsic \p name with arguments \p arg
-  /// and expected result type \p resultType. Return the result and a boolean
-  /// that, if true, indicates that the result must be freed after use.
-  std::pair<fir::ExtendedValue, bool>
-  genIntrinsicCall(llvm::StringRef name, std::optional<mlir::Type> resultType,
-                   llvm::ArrayRef<fir::ExtendedValue> arg);
-
-  /// Search a runtime function that is associated to the generic intrinsic name
-  /// and whose signature matches the intrinsic arguments and result types.
-  /// If no such runtime function is found but a runtime function associated
-  /// with the Fortran generic exists and has the same number of arguments,
-  /// conversions will be inserted before and/or after the call. This is to
-  /// mainly to allow 16 bits float support even-though little or no math
-  /// runtime is currently available for it.
-  mlir::Value genRuntimeCall(llvm::StringRef name, mlir::Type,
-                             llvm::ArrayRef<mlir::Value>);
-
-  using RuntimeCallGenerator = std::function<mlir::Value(
-      fir::FirOpBuilder &, mlir::Location, llvm::ArrayRef<mlir::Value>)>;
-  RuntimeCallGenerator
-  getRuntimeCallGenerator(llvm::StringRef name,
-                          mlir::FunctionType soughtFuncType);
-
-  void genAbort(llvm::ArrayRef<fir::ExtendedValue>);
-
-  /// Lowering for the ABS intrinsic. The ABS intrinsic expects one argument in
-  /// the llvm::ArrayRef. The ABS intrinsic is lowered into MLIR/FIR operation
-  /// if the argument is an integer, into llvm intrinsics if the argument is
-  /// real and to the `hypot` math routine if the argument is of complex type.
-  mlir::Value genAbs(mlir::Type, llvm::ArrayRef<mlir::Value>);
-  template <void (*CallRuntime)(fir::FirOpBuilder &, mlir::Location loc,
-                                mlir::Value, mlir::Value)>
-  fir::ExtendedValue genAdjustRtCall(mlir::Type,
-                                     llvm::ArrayRef<fir::ExtendedValue>);
-  mlir::Value genAimag(mlir::Type, llvm::ArrayRef<mlir::Value>);
-  mlir::Value genAint(mlir::Type, llvm::ArrayRef<mlir::Value>);
-  fir::ExtendedValue genAll(mlir::Type, llvm::ArrayRef<fir::ExtendedValue>);
-  fir::ExtendedValue genAllocated(mlir::Type,
-                                  llvm::ArrayRef<fir::ExtendedValue>);
-  mlir::Value genAnint(mlir::Type, llvm::ArrayRef<mlir::Value>);
-  fir::ExtendedValue genAny(mlir::Type, llvm::ArrayRef<fir::ExtendedValue>);
-  mlir::Value genAtand(mlir::Type, llvm::ArrayRef<mlir::Value>);
-  fir::ExtendedValue
-      genCommandArgumentCount(mlir::Type, llvm::ArrayRef<fir::ExtendedValue>);
-  fir::ExtendedValue genAssociated(mlir::Type,
-                                   llvm::ArrayRef<fir::ExtendedValue>);
-  fir::ExtendedValue genBesselJn(mlir::Type,
-                                 llvm::ArrayRef<fir::ExtendedValue>);
-  fir::ExtendedValue genBesselYn(mlir::Type,
-                                 llvm::ArrayRef<fir::ExtendedValue>);
-  /// Lower a bitwise comparison intrinsic using the given comparator.
-  template <mlir::arith::CmpIPredicate pred>
-  mlir::Value genBitwiseCompare(mlir::Type resultType,
-                                llvm::ArrayRef<mlir::Value> args);
-
-  mlir::Value genBtest(mlir::Type, llvm::ArrayRef<mlir::Value>);
-  mlir::Value genCeiling(mlir::Type, llvm::ArrayRef<mlir::Value>);
-  fir::ExtendedValue genChar(mlir::Type, llvm::ArrayRef<fir::ExtendedValue>);
-  template <mlir::arith::CmpIPredicate pred>
-  fir::ExtendedValue genCharacterCompare(mlir::Type,
-                                         llvm::ArrayRef<fir::ExtendedValue>);
-  mlir::Value genCmplx(mlir::Type, llvm::ArrayRef<mlir::Value>);
-  mlir::Value genConjg(mlir::Type, llvm::ArrayRef<mlir::Value>);
-  fir::ExtendedValue genCount(mlir::Type, llvm::ArrayRef<fir::ExtendedValue>);
-  void genCpuTime(llvm::ArrayRef<fir::ExtendedValue>);
-  fir::ExtendedValue genCshift(mlir::Type, llvm::ArrayRef<fir::ExtendedValue>);
-  fir::ExtendedValue genCAssociatedCFunPtr(mlir::Type,
-                                           llvm::ArrayRef<fir::ExtendedValue>);
-  fir::ExtendedValue genCAssociatedCPtr(mlir::Type,
-                                        llvm::ArrayRef<fir::ExtendedValue>);
-  void genCFPointer(llvm::ArrayRef<fir::ExtendedValue>);
-  fir::ExtendedValue genCFunLoc(mlir::Type, llvm::ArrayRef<fir::ExtendedValue>);
-  fir::ExtendedValue genCLoc(mlir::Type, llvm::ArrayRef<fir::ExtendedValue>);
-  void genDateAndTime(llvm::ArrayRef<fir::ExtendedValue>);
-  mlir::Value genDim(mlir::Type, llvm::ArrayRef<mlir::Value>);
-  fir::ExtendedValue genDotProduct(mlir::Type,
-                                   llvm::ArrayRef<fir::ExtendedValue>);
-  mlir::Value genDprod(mlir::Type, llvm::ArrayRef<mlir::Value>);
-  mlir::Value genDshiftl(mlir::Type, llvm::ArrayRef<mlir::Value>);
-  mlir::Value genDshiftr(mlir::Type, llvm::ArrayRef<mlir::Value>);
-  fir::ExtendedValue genEoshift(mlir::Type, llvm::ArrayRef<fir::ExtendedValue>);
-  void genExit(llvm::ArrayRef<fir::ExtendedValue>);
-  mlir::Value genExponent(mlir::Type, llvm::ArrayRef<mlir::Value>);
-  fir::ExtendedValue genExtendsTypeOf(mlir::Type,
-                                      llvm::ArrayRef<fir::ExtendedValue>);
-  template <Extremum, ExtremumBehavior>
-  mlir::Value genExtremum(mlir::Type, llvm::ArrayRef<mlir::Value>);
-  mlir::Value genFloor(mlir::Type, llvm::ArrayRef<mlir::Value>);
-  mlir::Value genFraction(mlir::Type resultType,
-                          mlir::ArrayRef<mlir::Value> args);
-  void genGetCommand(mlir::ArrayRef<fir::ExtendedValue> args);
-  void genGetCommandArgument(mlir::ArrayRef<fir::ExtendedValue> args);
-  void genGetEnvironmentVariable(llvm::ArrayRef<fir::ExtendedValue>);
-  fir::ExtendedValue genIall(mlir::Type, llvm::ArrayRef<fir::ExtendedValue>);
-  /// Lowering for the IAND intrinsic. The IAND intrinsic expects two arguments
-  /// in the llvm::ArrayRef.
-  mlir::Value genIand(mlir::Type, llvm::ArrayRef<mlir::Value>);
-  fir::ExtendedValue genIany(mlir::Type, llvm::ArrayRef<fir::ExtendedValue>);
-  mlir::Value genIbclr(mlir::Type, llvm::ArrayRef<mlir::Value>);
-  mlir::Value genIbits(mlir::Type, llvm::ArrayRef<mlir::Value>);
-  mlir::Value genIbset(mlir::Type, llvm::ArrayRef<mlir::Value>);
-  fir::ExtendedValue genIchar(mlir::Type, llvm::ArrayRef<fir::ExtendedValue>);
-  fir::ExtendedValue genFindloc(mlir::Type, llvm::ArrayRef<fir::ExtendedValue>);
-  mlir::Value genIeeeIsFinite(mlir::Type, llvm::ArrayRef<mlir::Value>);
-  mlir::Value genIeeeIsNormal(mlir::Type, llvm::ArrayRef<mlir::Value>);
-  template <mlir::arith::CmpIPredicate pred>
-  fir::ExtendedValue genIeeeTypeCompare(mlir::Type,
-                                        llvm::ArrayRef<fir::ExtendedValue>);
-  mlir::Value genIeor(mlir::Type, llvm::ArrayRef<mlir::Value>);
-  fir::ExtendedValue genIndex(mlir::Type, llvm::ArrayRef<fir::ExtendedValue>);
-  mlir::Value genIor(mlir::Type, llvm::ArrayRef<mlir::Value>);
-  fir::ExtendedValue genIparity(mlir::Type, llvm::ArrayRef<fir::ExtendedValue>);
-  fir::ExtendedValue genIsContiguous(mlir::Type,
-                                     llvm::ArrayRef<fir::ExtendedValue>);
-  template <Fortran::runtime::io::Iostat value>
-  mlir::Value genIsIostatValue(mlir::Type, llvm::ArrayRef<mlir::Value>);
-  mlir::Value genIsNan(mlir::Type, llvm::ArrayRef<mlir::Value>);
-  mlir::Value genIsFPClass(mlir::Type, llvm::ArrayRef<mlir::Value>,
-                           int fpclass);
-  mlir::Value genIshft(mlir::Type, llvm::ArrayRef<mlir::Value>);
-  mlir::Value genIshftc(mlir::Type, llvm::ArrayRef<mlir::Value>);
-  fir::ExtendedValue genLbound(mlir::Type, llvm::ArrayRef<fir::ExtendedValue>);
-  mlir::Value genLeadz(mlir::Type, llvm::ArrayRef<mlir::Value>);
-  fir::ExtendedValue genLen(mlir::Type, llvm::ArrayRef<fir::ExtendedValue>);
-  fir::ExtendedValue genLenTrim(mlir::Type, llvm::ArrayRef<fir::ExtendedValue>);
-  fir::ExtendedValue genLoc(mlir::Type, llvm::ArrayRef<fir::ExtendedValue>);
-  template <typename Shift>
-  mlir::Value genMask(mlir::Type, llvm::ArrayRef<mlir::Value>);
-  fir::ExtendedValue genMatmul(mlir::Type, llvm::ArrayRef<fir::ExtendedValue>);
-  fir::ExtendedValue genMatmulTranspose(mlir::Type,
-                                        llvm::ArrayRef<fir::ExtendedValue>);
-  fir::ExtendedValue genMaxloc(mlir::Type, llvm::ArrayRef<fir::ExtendedValue>);
-  fir::ExtendedValue genMaxval(mlir::Type, llvm::ArrayRef<fir::ExtendedValue>);
-  fir::ExtendedValue genMerge(mlir::Type, llvm::ArrayRef<fir::ExtendedValue>);
-  mlir::Value genMergeBits(mlir::Type, llvm::ArrayRef<mlir::Value>);
-  fir::ExtendedValue genMinloc(mlir::Type, llvm::ArrayRef<fir::ExtendedValue>);
-  fir::ExtendedValue genMinval(mlir::Type, llvm::ArrayRef<fir::ExtendedValue>);
-  mlir::Value genMod(mlir::Type, llvm::ArrayRef<mlir::Value>);
-  mlir::Value genModulo(mlir::Type, llvm::ArrayRef<mlir::Value>);
-  void genMoveAlloc(llvm::ArrayRef<fir::ExtendedValue>);
-  void genMvbits(llvm::ArrayRef<fir::ExtendedValue>);
-  mlir::Value genNearest(mlir::Type, llvm::ArrayRef<mlir::Value>);
-  mlir::Value genNint(mlir::Type, llvm::ArrayRef<mlir::Value>);
-  fir::ExtendedValue genNorm2(mlir::Type, llvm::ArrayRef<fir::ExtendedValue>);
-  mlir::Value genNot(mlir::Type, llvm::ArrayRef<mlir::Value>);
-  fir::ExtendedValue genNull(mlir::Type, llvm::ArrayRef<fir::ExtendedValue>);
-  fir::ExtendedValue genPack(mlir::Type, llvm::ArrayRef<fir::ExtendedValue>);
-  fir::ExtendedValue genParity(mlir::Type, llvm::ArrayRef<fir::ExtendedValue>);
-  mlir::Value genPopcnt(mlir::Type, llvm::ArrayRef<mlir::Value>);
-  mlir::Value genPoppar(mlir::Type, llvm::ArrayRef<mlir::Value>);
-  fir::ExtendedValue genPresent(mlir::Type, llvm::ArrayRef<fir::ExtendedValue>);
-  fir::ExtendedValue genProduct(mlir::Type, llvm::ArrayRef<fir::ExtendedValue>);
-  void genRandomInit(llvm::ArrayRef<fir::ExtendedValue>);
-  void genRandomNumber(llvm::ArrayRef<fir::ExtendedValue>);
-  void genRandomSeed(llvm::ArrayRef<fir::ExtendedValue>);
-  fir::ExtendedValue genReduce(mlir::Type, llvm::ArrayRef<fir::ExtendedValue>);
-  fir::ExtendedValue genRepeat(mlir::Type, llvm::ArrayRef<fir::ExtendedValue>);
-  fir::ExtendedValue genReshape(mlir::Type, llvm::ArrayRef<fir::ExtendedValue>);
-  mlir::Value genRRSpacing(mlir::Type resultType,
-                           llvm::ArrayRef<mlir::Value> args);
-  fir::ExtendedValue genSameTypeAs(mlir::Type,
-                                   llvm::ArrayRef<fir::ExtendedValue>);
-  mlir::Value genScale(mlir::Type, llvm::ArrayRef<mlir::Value>);
-  fir::ExtendedValue genScan(mlir::Type, llvm::ArrayRef<fir::ExtendedValue>);
-  mlir::Value genSelectedIntKind(mlir::Type, llvm::ArrayRef<mlir::Value>);
-  mlir::Value genSelectedRealKind(mlir::Type, llvm::ArrayRef<mlir::Value>);
-  mlir::Value genSetExponent(mlir::Type resultType,
-                             llvm::ArrayRef<mlir::Value> args);
-  template <typename Shift>
-  mlir::Value genShift(mlir::Type resultType, llvm::ArrayRef<mlir::Value>);
-  mlir::Value genShiftA(mlir::Type resultType, llvm::ArrayRef<mlir::Value>);
-  mlir::Value genSign(mlir::Type, llvm::ArrayRef<mlir::Value>);
-  fir::ExtendedValue genSize(mlir::Type, llvm::ArrayRef<fir::ExtendedValue>);
-  mlir::Value genSpacing(mlir::Type resultType,
-                         llvm::ArrayRef<mlir::Value> args);
-  fir::ExtendedValue genSpread(mlir::Type, llvm::ArrayRef<fir::ExtendedValue>);
-  fir::ExtendedValue genStorageSize(mlir::Type,
-                                    llvm::ArrayRef<fir::ExtendedValue>);
-  fir::ExtendedValue genSum(mlir::Type, llvm::ArrayRef<fir::ExtendedValue>);
-  void genSystemClock(llvm::ArrayRef<fir::ExtendedValue>);
-  mlir::Value genTrailz(mlir::Type, llvm::ArrayRef<mlir::Value>);
-  fir::ExtendedValue genTransfer(mlir::Type,
-                                 llvm::ArrayRef<fir::ExtendedValue>);
-  fir::ExtendedValue genTranspose(mlir::Type,
-                                  llvm::ArrayRef<fir::ExtendedValue>);
-  fir::ExtendedValue genTrim(mlir::Type, llvm::ArrayRef<fir::ExtendedValue>);
-  fir::ExtendedValue genUbound(mlir::Type, llvm::ArrayRef<fir::ExtendedValue>);
-  fir::ExtendedValue genUnpack(mlir::Type, llvm::ArrayRef<fir::ExtendedValue>);
-  fir::ExtendedValue genVerify(mlir::Type, llvm::ArrayRef<fir::ExtendedValue>);
-  /// Implement all conversion functions like DBLE, the first argument is
-  /// the value to convert. There may be an additional KIND arguments that
-  /// is ignored because this is already reflected in the result type.
-  mlir::Value genConversion(mlir::Type, llvm::ArrayRef<mlir::Value>);
-
-  // PPC intrinsic handlers.
-  template <bool isImm>
-  void genMtfsf(llvm::ArrayRef<fir::ExtendedValue>);
-
-  /// 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.
-  ///  - "FC funcChar" is a callback to generate the character runtime call.
-  /// Helper for MinLoc/MaxLoc.
-  template <typename FN, typename FD>
-  fir::ExtendedValue genExtremumloc(FN func, FD funcDim, llvm::StringRef errMsg,
-                                    mlir::Type,
-                                    llvm::ArrayRef<fir::ExtendedValue>);
-  template <typename FN, typename FD, typename FC>
-  /// Helper for MinVal/MaxVal.
-  fir::ExtendedValue genExtremumVal(FN func, FD funcDim, FC funcChar,
-                                    llvm::StringRef errMsg,
-                                    mlir::Type resultType,
-                                    llvm::ArrayRef<fir::ExtendedValue> args);
-  /// Process calls to Product, Sum, IAll, IAny, IParity intrinsic functions
-  template <typename FN, typename FD>
-  fir::ExtendedValue genReduction(FN func, FD funcDim, llvm::StringRef errMsg,
-                                  mlir::Type resultType,
-                                  llvm::ArrayRef<fir::ExtendedValue> args);
-
-  /// Define the 
diff erent FIR generators that can be mapped to intrinsic to
-  /// generate the related code.
-  using ElementalGenerator = decltype(&IntrinsicLibrary::genAbs);
-  using ExtendedGenerator = decltype(&IntrinsicLibrary::genLenTrim);
-  using SubroutineGenerator = decltype(&IntrinsicLibrary::genDateAndTime);
-  using Generator =
-      std::variant<ElementalGenerator, ExtendedGenerator, SubroutineGenerator>;
-
-  /// All generators can be outlined. This will build a function named
-  /// "fir."+ <generic name> + "." + <result type code> and generate the
-  /// intrinsic implementation inside instead of at the intrinsic call sites.
-  /// This can be used to keep the FIR more readable. Only one function will
-  /// be generated for all the similar calls in a program.
-  /// If the Generator is nullptr, the wrapper uses genRuntimeCall.
-  template <typename GeneratorType>
-  mlir::Value outlineInWrapper(GeneratorType, llvm::StringRef name,
-                               mlir::Type resultType,
-                               llvm::ArrayRef<mlir::Value> args);
-  template <typename GeneratorType>
-  fir::ExtendedValue
-  outlineInExtendedWrapper(GeneratorType, llvm::StringRef name,
-                           std::optional<mlir::Type> resultType,
-                           llvm::ArrayRef<fir::ExtendedValue> args);
-
-  template <typename GeneratorType>
-  mlir::func::FuncOp getWrapper(GeneratorType, llvm::StringRef name,
-                                mlir::FunctionType,
-                                bool loadRefArguments = false);
-
-  /// Generate calls to ElementalGenerator, handling the elemental aspects
-  template <typename GeneratorType>
-  fir::ExtendedValue
-  genElementalCall(GeneratorType, llvm::StringRef name, mlir::Type resultType,
-                   llvm::ArrayRef<fir::ExtendedValue> args, bool outline);
-
-  /// Helper to invoke code generator for the intrinsics given arguments.
-  mlir::Value invokeGenerator(ElementalGenerator generator,
-                              mlir::Type resultType,
-                              llvm::ArrayRef<mlir::Value> args);
-  mlir::Value invokeGenerator(RuntimeCallGenerator generator,
-                              mlir::Type resultType,
-                              llvm::ArrayRef<mlir::Value> args);
-  mlir::Value invokeGenerator(ExtendedGenerator generator,
-                              mlir::Type resultType,
-                              llvm::ArrayRef<mlir::Value> args);
-  mlir::Value invokeGenerator(SubroutineGenerator generator,
-                              llvm::ArrayRef<mlir::Value> args);
-
-  /// Get pointer to unrestricted intrinsic. Generate the related unrestricted
-  /// intrinsic if it is not defined yet.
-  mlir::SymbolRefAttr
-  getUnrestrictedIntrinsicSymbolRefAttr(llvm::StringRef name,
-                                        mlir::FunctionType signature);
-
-  /// Helper function for generating code clean-up for result descriptors
-  fir::ExtendedValue readAndAddCleanUp(fir::MutableBoxValue resultMutableBox,
-                                       mlir::Type resultType,
-                                       llvm::StringRef errMsg);
-
-  void setResultMustBeFreed() { resultMustBeFreed = true; }
-
-  fir::FirOpBuilder &builder;
-  mlir::Location loc;
-  bool resultMustBeFreed = false;
-};
-
-struct IntrinsicDummyArgument {
-  const char *name = nullptr;
-  fir::LowerIntrinsicArgAs lowerAs = fir::LowerIntrinsicArgAs::Value;
-  bool handleDynamicOptional = false;
-};
-
-/// This is shared by intrinsics and intrinsic module procedures.
-struct fir::IntrinsicArgumentLoweringRules {
-  /// There is no more than 7 non repeated arguments in Fortran intrinsics.
-  IntrinsicDummyArgument args[7];
-  constexpr bool hasDefaultRules() const { return args[0].name == nullptr; }
-};
-
-/// Structure describing what needs to be done to lower intrinsic or intrinsic
-/// module procedure "name".
-struct IntrinsicHandler {
-  const char *name;
-  IntrinsicLibrary::Generator generator;
-  // The following may be omitted in the table below.
-  fir::IntrinsicArgumentLoweringRules argLoweringRules = {};
-  bool isElemental = true;
-  /// Code heavy intrinsic can be outlined to make FIR
-  /// more readable.
-  bool outline = false;
-};
-
 constexpr auto asValue = fir::LowerIntrinsicArgAs::Value;
 constexpr auto asAddr = fir::LowerIntrinsicArgAs::Addr;
 constexpr auto asBox = fir::LowerIntrinsicArgAs::Box;
@@ -943,18 +580,6 @@ static llvm::cl::opt<bool>
                                       "dialect to lower complex operations"),
                        llvm::cl::init(false));
 
-struct RuntimeFunction {
-  // llvm::StringRef comparison operator are not constexpr, so use string_view.
-  using Key = std::string_view;
-  // Needed for implicit compare with keys.
-  constexpr operator Key() const { return key; }
-  Key key; // intrinsic name
-
-  // Name of a runtime function that implements the operation.
-  llvm::StringRef symbol;
-  fir::runtime::FuncTypeBuilderFunc typeGenerator;
-};
-
 static mlir::FunctionType genF32F32FuncType(mlir::MLIRContext *context) {
   mlir::Type t = mlir::FloatType::getF32(context);
   return mlir::FunctionType::get(context, {t}, {t});
@@ -1101,30 +726,6 @@ genComplexComplexIntFuncType(mlir::MLIRContext *context) {
   return mlir::FunctionType::get(context, {ctype, itype}, {ctype});
 }
 
-/// Callback type for generating lowering for a math operation.
-using MathGeneratorTy = mlir::Value (*)(fir::FirOpBuilder &, mlir::Location,
-                                        llvm::StringRef, mlir::FunctionType,
-                                        llvm::ArrayRef<mlir::Value>);
-
-struct MathOperation {
-  // llvm::StringRef comparison operator are not constexpr, so use string_view.
-  using Key = std::string_view;
-  // Needed for implicit compare with keys.
-  constexpr operator Key() const { return key; }
-  // Intrinsic name.
-  Key key;
-
-  // Name of a runtime function that implements the operation.
-  llvm::StringRef runtimeFunc;
-  fir::runtime::FuncTypeBuilderFunc typeGenerator;
-
-  // A callback to generate FIR for the intrinsic defined by 'key'.
-  // A callback may generate either dedicated MLIR operation(s) or
-  // a function call to a runtime function with name defined by
-  // 'runtimeFunc'.
-  MathGeneratorTy funcGenerator;
-};
-
 static mlir::Value genLibCall(fir::FirOpBuilder &builder, mlir::Location loc,
                               llvm::StringRef libFuncName,
                               mlir::FunctionType libFuncType,
@@ -5683,8 +5284,8 @@ void IntrinsicLibrary::genMtfsf(llvm::ArrayRef<fir::ExtendedValue> args) {
 // procedure.
 //===----------------------------------------------------------------------===//
 
-const fir::IntrinsicArgumentLoweringRules *
-fir::getIntrinsicArgumentLowering(llvm::StringRef specificName) {
+const IntrinsicArgumentLoweringRules *
+getIntrinsicArgumentLowering(llvm::StringRef specificName) {
   llvm::StringRef name = genericName(specificName);
   if (const IntrinsicHandler *handler = findIntrinsicHandler(name))
     if (!handler->argLoweringRules.hasDefaultRules())
@@ -5695,8 +5296,8 @@ fir::getIntrinsicArgumentLowering(llvm::StringRef specificName) {
 /// Return how argument \p argName should be lowered given the rules for the
 /// intrinsic function.
 fir::ArgLoweringRule
-fir::lowerIntrinsicArgumentAs(const IntrinsicArgumentLoweringRules &rules,
-                              unsigned position) {
+lowerIntrinsicArgumentAs(const IntrinsicArgumentLoweringRules &rules,
+                         unsigned position) {
   assert(position < sizeof(rules.args) / (sizeof(decltype(*rules.args))) &&
          "invalid argument");
   return {rules.args[position].lowerAs,
@@ -5708,37 +5309,36 @@ fir::lowerIntrinsicArgumentAs(const IntrinsicArgumentLoweringRules &rules,
 //===----------------------------------------------------------------------===//
 
 std::pair<fir::ExtendedValue, bool>
-fir::genIntrinsicCall(fir::FirOpBuilder &builder, mlir::Location loc,
-                      llvm::StringRef name,
-                      std::optional<mlir::Type> resultType,
-                      llvm::ArrayRef<fir::ExtendedValue> args) {
+genIntrinsicCall(fir::FirOpBuilder &builder, mlir::Location loc,
+                 llvm::StringRef name, std::optional<mlir::Type> resultType,
+                 llvm::ArrayRef<fir::ExtendedValue> args) {
   return IntrinsicLibrary{builder, loc}.genIntrinsicCall(name, resultType,
                                                          args);
 }
 
-mlir::Value fir::genMax(fir::FirOpBuilder &builder, mlir::Location loc,
-                        llvm::ArrayRef<mlir::Value> args) {
+mlir::Value genMax(fir::FirOpBuilder &builder, mlir::Location loc,
+                   llvm::ArrayRef<mlir::Value> args) {
   assert(args.size() > 0 && "max requires at least one argument");
   return IntrinsicLibrary{builder, loc}
       .genExtremum<Extremum::Max, ExtremumBehavior::MinMaxss>(args[0].getType(),
                                                               args);
 }
 
-mlir::Value fir::genMin(fir::FirOpBuilder &builder, mlir::Location loc,
-                        llvm::ArrayRef<mlir::Value> args) {
+mlir::Value genMin(fir::FirOpBuilder &builder, mlir::Location loc,
+                   llvm::ArrayRef<mlir::Value> args) {
   assert(args.size() > 0 && "min requires at least one argument");
   return IntrinsicLibrary{builder, loc}
       .genExtremum<Extremum::Min, ExtremumBehavior::MinMaxss>(args[0].getType(),
                                                               args);
 }
 
-mlir::Value fir::genDivC(fir::FirOpBuilder &builder, mlir::Location loc,
-                         mlir::Type type, mlir::Value x, mlir::Value y) {
+mlir::Value genDivC(fir::FirOpBuilder &builder, mlir::Location loc,
+                    mlir::Type type, mlir::Value x, mlir::Value y) {
   return IntrinsicLibrary{builder, loc}.genRuntimeCall("divc", type, {x, y});
 }
 
-mlir::Value fir::genPow(fir::FirOpBuilder &builder, mlir::Location loc,
-                        mlir::Type type, mlir::Value x, mlir::Value y) {
+mlir::Value genPow(fir::FirOpBuilder &builder, mlir::Location loc,
+                   mlir::Type type, mlir::Value x, mlir::Value y) {
   // TODO: since there is no libm version of pow with integer exponent,
   //       we have to provide an alternative implementation for
   //       "precise/strict" FP mode.
@@ -5749,9 +5349,11 @@ mlir::Value fir::genPow(fir::FirOpBuilder &builder, mlir::Location loc,
   return IntrinsicLibrary{builder, loc}.genRuntimeCall("pow", type, {x, y});
 }
 
-mlir::SymbolRefAttr fir::getUnrestrictedIntrinsicSymbolRefAttr(
-    fir::FirOpBuilder &builder, mlir::Location loc, llvm::StringRef name,
-    mlir::FunctionType signature) {
+mlir::SymbolRefAttr
+getUnrestrictedIntrinsicSymbolRefAttr(fir::FirOpBuilder &builder,
+                                      mlir::Location loc, llvm::StringRef name,
+                                      mlir::FunctionType signature) {
   return IntrinsicLibrary{builder, loc}.getUnrestrictedIntrinsicSymbolRefAttr(
       name, signature);
 }
+} // namespace fir


        


More information about the flang-commits mailing list