[flang-commits] [flang] 9f35657 - [flang] Lower Fortran math intrinsic operations into MLIR ops or libm calls.

Slava Zakharin via flang-commits flang-commits at lists.llvm.org
Tue Jun 28 13:37:59 PDT 2022


Author: Slava Zakharin
Date: 2022-06-28T13:32:19-07:00
New Revision: 9f35657983c5f8370f276156f0351f98ae5296bf

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

LOG: [flang] Lower Fortran math intrinsic operations into MLIR ops or libm calls.

Added new -lower-math-early option that defaults to 'true' that matches
the current math lowering scheme. If set to 'false', the intrinsic math
operations will be lowered to MLIR operations, which should potentially
enable more MLIR optimizations, or libm calls, if there is no corresponding
MLIR operation exists or if "precise" mode is requested.
The generated math MLIR operations are then converted to LLVM dialect
during codegen phase.

The -lower-math-early option is not exposed to users currently. I plan to
get rid of the "early" lowering completely, when "late" lowering
is robust enough to support all math intrinsics that are currently
supported via pgmath. So "late" mode will become default and -lower-math-early
option will not be needed. This will effectively eliminate the mandatory
dependency on pgmath in Fortran lowering, but this is WIP.

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

Added: 
    flang/test/Intrinsics/late-math-codegen.fir
    flang/test/Lower/late-math-lowering.f90

Modified: 
    flang/include/flang/Optimizer/Support/InitFIR.h
    flang/lib/Lower/IntrinsicCall.cpp
    flang/lib/Optimizer/CodeGen/CMakeLists.txt
    flang/lib/Optimizer/CodeGen/CodeGen.cpp
    flang/test/Lower/Intrinsics/exp.f90
    flang/test/Lower/Intrinsics/log.f90
    flang/test/Lower/Intrinsics/math-runtime-options.f90
    flang/test/Lower/array-expression-slice-1.f90
    flang/test/Lower/llvm-math.f90
    flang/test/Lower/sqrt.f90
    flang/test/Lower/trigonometric-intrinsics.f90

Removed: 
    


################################################################################
diff  --git a/flang/include/flang/Optimizer/Support/InitFIR.h b/flang/include/flang/Optimizer/Support/InitFIR.h
index f31251842a463..9b3b6311db99b 100644
--- a/flang/include/flang/Optimizer/Support/InitFIR.h
+++ b/flang/include/flang/Optimizer/Support/InitFIR.h
@@ -28,7 +28,8 @@ namespace fir::support {
   mlir::AffineDialect, FIROpsDialect, mlir::acc::OpenACCDialect,               \
       mlir::omp::OpenMPDialect, mlir::scf::SCFDialect,                         \
       mlir::arith::ArithmeticDialect, mlir::cf::ControlFlowDialect,            \
-      mlir::func::FuncDialect, mlir::vector::VectorDialect
+      mlir::func::FuncDialect, mlir::vector::VectorDialect,                    \
+      mlir::math::MathDialect
 
 // The definitive list of dialects used by flang.
 #define FLANG_DIALECT_LIST                                                     \

diff  --git a/flang/lib/Lower/IntrinsicCall.cpp b/flang/lib/Lower/IntrinsicCall.cpp
index 8b922e407db5f..357bbec788625 100644
--- a/flang/lib/Lower/IntrinsicCall.cpp
+++ b/flang/lib/Lower/IntrinsicCall.cpp
@@ -35,6 +35,7 @@
 #include "flang/Optimizer/Dialect/FIROpsSupport.h"
 #include "flang/Optimizer/Support/FatalError.h"
 #include "mlir/Dialect/LLVMIR/LLVMDialect.h"
+#include "mlir/Dialect/Math/IR/Math.h"
 #include "llvm/Support/CommandLine.h"
 #include "llvm/Support/Debug.h"
 
@@ -960,8 +961,23 @@ static llvm::cl::opt<bool> outlineAllIntrinsics(
 // Math runtime description and matching utility
 //===----------------------------------------------------------------------===//
 
-/// Command line option to modify math runtime version used to implement
-/// intrinsics.
+/// Command line option to control how math operations are lowered
+/// into MLIR.
+/// Going forward, most of the math operations have to be lowered
+/// to some MLIR dialect operations or libm calls, if the corresponding
+/// MLIR operation is not available or not reasonable to create
+/// (e.g. there are no known optimization opportunities for the math
+/// operation in MLIR).
+///
+/// In general, exposing MLIR operations early can potentially enable more
+/// MLIR optimizations.
+llvm::cl::opt<bool> lowerEarlyToLibCall(
+    "lower-math-early",
+    llvm::cl::desc("Controls when to lower Math intrinsics to library calls"),
+    llvm::cl::init(true));
+
+/// Command line option to modify math runtime behavior used to implement
+/// intrinsics. This option applies both to early and late math-lowering modes.
 enum MathRuntimeVersion {
   fastVersion,
   relaxedVersion,
@@ -969,11 +985,11 @@ enum MathRuntimeVersion {
   llvmOnly
 };
 llvm::cl::opt<MathRuntimeVersion> mathRuntimeVersion(
-    "math-runtime", llvm::cl::desc("Select math runtime version:"),
+    "math-runtime", llvm::cl::desc("Select math operations' runtime behavior:"),
     llvm::cl::values(
-        clEnumValN(fastVersion, "fast", "use pgmath fast runtime"),
-        clEnumValN(relaxedVersion, "relaxed", "use pgmath relaxed runtime"),
-        clEnumValN(preciseVersion, "precise", "use pgmath precise runtime"),
+        clEnumValN(fastVersion, "fast", "use fast runtime behavior"),
+        clEnumValN(relaxedVersion, "relaxed", "use relaxed runtime behavior"),
+        clEnumValN(preciseVersion, "precise", "use precise runtime behavior"),
         clEnumValN(llvmOnly, "llvm",
                    "only use LLVM intrinsics (may be incomplete)")),
     llvm::cl::init(fastVersion));
@@ -984,6 +1000,8 @@ struct RuntimeFunction {
   // 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;
 };
@@ -1050,9 +1068,168 @@ static mlir::FunctionType genIntF32FuncType(mlir::MLIRContext *context) {
   return mlir::FunctionType::get(context, {t}, {r});
 }
 
-// TODO : Fill-up this table with more intrinsic.
+template <int Bits>
+static mlir::FunctionType genF64F64IntFuncType(mlir::MLIRContext *context) {
+  auto ftype = mlir::FloatType::getF64(context);
+  auto itype = mlir::IntegerType::get(context, Bits);
+  return mlir::FunctionType::get(context, {ftype, itype}, {ftype});
+}
+
+template <int Bits>
+static mlir::FunctionType genF32F32IntFuncType(mlir::MLIRContext *context) {
+  auto ftype = mlir::FloatType::getF32(context);
+  auto itype = mlir::IntegerType::get(context, Bits);
+  return mlir::FunctionType::get(context, {ftype, itype}, {ftype});
+}
+
+/// 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,
+                              llvm::ArrayRef<mlir::Value> args) {
+  LLVM_DEBUG(llvm::dbgs() << "Generating '" << libFuncName
+                          << "' call with type ";
+             libFuncType.dump(); llvm::dbgs() << "\n");
+  mlir::func::FuncOp funcOp =
+      builder.addNamedFunction(loc, libFuncName, libFuncType);
+  // TODO: ensure 'strictfp' setting on the call for "precise/strict"
+  //       FP mode. Set appropriate Fast-Math Flags otherwise.
+  // TODO: we should also mark as many libm function as possible
+  //       with 'pure' attribute (of course, not in strict FP mode).
+  auto libCall = builder.create<fir::CallOp>(loc, funcOp, args);
+  LLVM_DEBUG(libCall.dump(); llvm::dbgs() << "\n");
+  return libCall.getResult(0);
+}
+
+template <typename T>
+static mlir::Value genMathOp(fir::FirOpBuilder &builder, mlir::Location loc,
+                             llvm::StringRef mathLibFuncName,
+                             mlir::FunctionType mathLibFuncType,
+                             llvm::ArrayRef<mlir::Value> 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
+  //       MLIR inlining we can distiguish operation that were
+  //       compiled with 
diff erent settings.
+  //       Suggestion:
+  //         * For "relaxed" FP mode set all Fast-Math Flags
+  //           (see "[RFC] FastMath flags support in MLIR (arith dialect)"
+  //           topic at discourse.llvm.org).
+  //         * For "fast" FP mode set all Fast-Math Flags except 'afn'.
+  //         * For "precise/strict" FP mode generate fir.calls to libm
+  //           entries and annotate them with an attribute that will
+  //           end up transformed into 'strictfp' LLVM attribute (TBD).
+  //           Elsewhere, "precise/strict" FP mode should also set
+  //           'strictfp' for all user functions and calls so that
+  //           LLVM backend does the right job.
+  //         * Operations that cannot be reasonably optimized in MLIR
+  //           can be also lowered to libm calls for "fast" and "relaxed"
+  //           modes.
+  mlir::Value result;
+  if (mathRuntimeVersion == preciseVersion) {
+    result = genLibCall(builder, loc, mathLibFuncName, mathLibFuncType, args);
+  } else {
+    LLVM_DEBUG(llvm::dbgs() << "Generating '" << mathLibFuncName
+                            << "' operation with type ";
+               mathLibFuncType.dump(); llvm::dbgs() << "\n");
+    result = builder.create<T>(loc, args);
+  }
+  LLVM_DEBUG(result.dump(); llvm::dbgs() << "\n");
+  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", genF32F32FuncType, genMathOp<mlir::math::AbsOp>},
+    {"abs", "fabs", genF64F64FuncType, genMathOp<mlir::math::AbsOp>},
+    // llvm.trunc behaves the same way as libm's trunc.
+    {"aint", "llvm.trunc.f32", genF32F32FuncType, genLibCall},
+    {"aint", "llvm.trunc.f64", genF64F64FuncType, genLibCall},
+    // llvm.round behaves the same way as libm's round.
+    {"anint", "llvm.round.f32", genF32F32FuncType,
+     genMathOp<mlir::LLVM::RoundOp>},
+    {"anint", "llvm.round.f64", genF64F64FuncType,
+     genMathOp<mlir::LLVM::RoundOp>},
+    {"atan", "atanf", genF32F32FuncType, genMathOp<mlir::math::AtanOp>},
+    {"atan", "atan", genF64F64FuncType, genMathOp<mlir::math::AtanOp>},
+    {"atan2", "atan2f", genF32F32F32FuncType, genMathOp<mlir::math::Atan2Op>},
+    {"atan2", "atan2", genF64F64F64FuncType, genMathOp<mlir::math::Atan2Op>},
+    // math::CeilOp returns a real, while Fortran CEILING returns integer.
+    {"ceil", "ceilf", genF32F32FuncType, genMathOp<mlir::math::CeilOp>},
+    {"ceil", "ceil", genF64F64FuncType, genMathOp<mlir::math::CeilOp>},
+    {"cos", "cosf", genF32F32FuncType, genMathOp<mlir::math::CosOp>},
+    {"cos", "cos", genF64F64FuncType, genMathOp<mlir::math::CosOp>},
+    {"erf", "erff", genF32F32FuncType, genMathOp<mlir::math::ErfOp>},
+    {"erf", "erf", genF64F64FuncType, genMathOp<mlir::math::ErfOp>},
+    {"exp", "expf", genF32F32FuncType, genMathOp<mlir::math::ExpOp>},
+    {"exp", "exp", genF64F64FuncType, genMathOp<mlir::math::ExpOp>},
+    // math::FloorOp returns a real, while Fortran FLOOR returns integer.
+    {"floor", "floorf", genF32F32FuncType, genMathOp<mlir::math::FloorOp>},
+    {"floor", "floor", genF64F64FuncType, genMathOp<mlir::math::FloorOp>},
+    {"hypot", "hypotf", genF32F32F32FuncType, genLibCall},
+    {"hypot", "hypot", genF64F64F64FuncType, genLibCall},
+    {"log", "logf", genF32F32FuncType, genMathOp<mlir::math::LogOp>},
+    {"log", "log", genF64F64FuncType, genMathOp<mlir::math::LogOp>},
+    {"log10", "log10f", genF32F32FuncType, genMathOp<mlir::math::Log10Op>},
+    {"log10", "log10", genF64F64FuncType, genMathOp<mlir::math::Log10Op>},
+    // llvm.lround behaves the same way as libm's lround.
+    {"nint", "llvm.lround.i64.f64", genIntF64FuncType<64>, genLibCall},
+    {"nint", "llvm.lround.i64.f32", genIntF32FuncType<64>, genLibCall},
+    {"nint", "llvm.lround.i32.f64", genIntF64FuncType<32>, genLibCall},
+    {"nint", "llvm.lround.i32.f32", genIntF32FuncType<32>, genLibCall},
+    {"pow", "powf", genF32F32F32FuncType, genMathOp<mlir::math::PowFOp>},
+    {"pow", "pow", genF64F64F64FuncType, genMathOp<mlir::math::PowFOp>},
+    // TODO: add PowIOp in math and complex dialects.
+    {"pow", "llvm.powi.f32.i32", genF32F32IntFuncType<32>, genLibCall},
+    {"pow", "llvm.powi.f64.i32", genF64F64IntFuncType<32>, genLibCall},
+    {"sign", "copysignf", genF32F32F32FuncType,
+     genMathOp<mlir::math::CopySignOp>},
+    {"sign", "copysign", genF64F64F64FuncType,
+     genMathOp<mlir::math::CopySignOp>},
+    {"sin", "sinf", genF32F32FuncType, genMathOp<mlir::math::SinOp>},
+    {"sin", "sin", genF64F64FuncType, genMathOp<mlir::math::SinOp>},
+    {"sqrt", "sqrtf", genF32F32FuncType, genMathOp<mlir::math::SqrtOp>},
+    {"sqrt", "sqrt", genF64F64FuncType, genMathOp<mlir::math::SqrtOp>},
+    {"tanh", "tanhf", genF32F32FuncType, genMathOp<mlir::math::TanhOp>},
+    {"tanh", "tanh", genF64F64FuncType, genMathOp<mlir::math::TanhOp>},
+};
+
 // Note: These are also defined as operations in LLVM dialect. See if this
 // can be use and has advantages.
+// TODO: remove this table, since the late math lowering should
+//       replace it and generate proper MLIR operations rather
+//       than llvm intrinsic calls, which still look like generic
+//       calls to MLIR and do not enable many optimizations.
+//       When late math lowering is able to handle all math operations
+//       described in pgmath.h.inc and in the table below, we can
+//       switch to it by default.
 static constexpr RuntimeFunction llvmIntrinsics[] = {
     {"abs", "llvm.fabs.f32", genF32F32FuncType},
     {"abs", "llvm.fabs.f64", genF64F64FuncType},
@@ -1251,7 +1428,7 @@ static mlir::func::FuncOp getFuncOp(mlir::Location loc,
 /// function type and that will not imply narrowing arguments or extending the
 /// result.
 /// If nothing is found, the mlir::func::FuncOp will contain a nullptr.
-mlir::func::FuncOp searchFunctionInLibrary(
+static mlir::func::FuncOp searchFunctionInLibrary(
     mlir::Location loc, fir::FirOpBuilder &builder,
     const Fortran::common::StaticMultimapView<RuntimeFunction> &lib,
     llvm::StringRef name, mlir::FunctionType funcType,
@@ -1274,6 +1451,77 @@ mlir::func::FuncOp searchFunctionInLibrary(
   return {};
 }
 
+using RtMap = Fortran::common::StaticMultimapView<MathOperation>;
+static constexpr RtMap mathOps(mathOperations);
+static_assert(mathOps.Verify() && "map must be sorted");
+
+/// Look for a MathOperation entry specifying how to lower a mathematical
+/// operation defined by \p name with its result' and operands' types
+/// specified in the form of a FunctionType \p funcType.
+/// If exact match for the given types is found, then the function
+/// returns a pointer to the corresponding MathOperation.
+/// Otherwise, the function returns nullptr.
+/// If there is a MathOperation that can be used with additional
+/// type casts for the operands or/and result (non-exact match),
+/// then it is returned via \p bestNearMatch argument, and
+/// \p bestMatchDistance specifies the FunctionDistance between
+/// the requested operation and the non-exact match.
+static const MathOperation *
+searchMathOperation(fir::FirOpBuilder &builder, llvm::StringRef name,
+                    mlir::FunctionType funcType,
+                    const MathOperation **bestNearMatch,
+                    FunctionDistance &bestMatchDistance) {
+  auto range = mathOps.equal_range(name);
+  for (auto iter = range.first; iter != range.second && iter; ++iter) {
+    const auto &impl = *iter;
+    auto implType = impl.typeGenerator(builder.getContext());
+    if (funcType == implType)
+      return &impl; // exact match
+
+    FunctionDistance distance(funcType, implType);
+    if (distance.isSmallerThan(bestMatchDistance)) {
+      *bestNearMatch = &impl;
+      bestMatchDistance = std::move(distance);
+    }
+  }
+  return nullptr;
+}
+
+/// Implementation of the operation defined by \p name with type
+/// \p funcType is not precise, and the actual available implementation
+/// is \p distance away from the requested. If using the available
+/// implementation results in a precision loss, emit an error message
+/// with the given code location \p loc.
+static void checkPrecisionLoss(llvm::StringRef name,
+                               mlir::FunctionType funcType,
+                               const FunctionDistance &distance,
+                               mlir::Location loc) {
+  if (!distance.isLosingPrecision())
+    return;
+
+  // Using this runtime version requires narrowing the arguments
+  // or extending the result. It is not numerically safe. There
+  // is currently no quad math library that was described in
+  // lowering and could be used here. Emit an error and continue
+  // generating the code with the narrowing cast so that the user
+  // can get a complete list of the problematic intrinsic calls.
+  std::string message("TODO: no math runtime available for '");
+  llvm::raw_string_ostream sstream(message);
+  if (name == "pow") {
+    assert(funcType.getNumInputs() == 2 && "power operator has two arguments");
+    sstream << funcType.getInput(0) << " ** " << funcType.getInput(1);
+  } else {
+    sstream << name << "(";
+    if (funcType.getNumInputs() > 0)
+      sstream << funcType.getInput(0);
+    for (mlir::Type argType : funcType.getInputs().drop_front())
+      sstream << ", " << argType;
+    sstream << ")";
+  }
+  sstream << "'";
+  mlir::emitError(loc, message);
+}
+
 /// Search runtime for the best runtime function given an intrinsic name
 /// and interface. The interface may not be a perfect match in which case
 /// the caller is responsible to insert argument and return value conversions.
@@ -1292,6 +1540,7 @@ static mlir::func::FuncOp getRuntimeFunction(mlir::Location loc,
   static_assert(pgmathR.Verify() && "map must be sorted");
   static constexpr RtMap pgmathP(pgmathPrecise);
   static_assert(pgmathP.Verify() && "map must be sorted");
+
   if (mathRuntimeVersion == fastVersion) {
     match = searchFunctionInLibrary(loc, builder, pgmathF, name, funcType,
                                     &bestNearMatch, bestMatchDistance);
@@ -1317,30 +1566,7 @@ static mlir::func::FuncOp getRuntimeFunction(mlir::Location loc,
     return exactMatch;
 
   if (bestNearMatch != nullptr) {
-    if (bestMatchDistance.isLosingPrecision()) {
-      // Using this runtime version requires narrowing the arguments
-      // or extending the result. It is not numerically safe. There
-      // is currently no quad math library that was described in
-      // lowering and could be used here. Emit an error and continue
-      // generating the code with the narrowing cast so that the user
-      // can get a complete list of the problematic intrinsic calls.
-      std::string message("TODO: no math runtime available for '");
-      llvm::raw_string_ostream sstream(message);
-      if (name == "pow") {
-        assert(funcType.getNumInputs() == 2 &&
-               "power operator has two arguments");
-        sstream << funcType.getInput(0) << " ** " << funcType.getInput(1);
-      } else {
-        sstream << name << "(";
-        if (funcType.getNumInputs() > 0)
-          sstream << funcType.getInput(0);
-        for (mlir::Type argType : funcType.getInputs().drop_front())
-          sstream << ", " << argType;
-        sstream << ")";
-      }
-      sstream << "'";
-      mlir::emitError(loc, message);
-    }
+    checkPrecisionLoss(name, funcType, bestMatchDistance, loc);
     return getFuncOp(loc, builder, *bestNearMatch);
   }
   return {};
@@ -1578,7 +1804,7 @@ IntrinsicLibrary::genIntrinsicCall(llvm::StringRef specificName,
   IntrinsicLibrary::RuntimeCallGenerator runtimeCallGenerator =
       getRuntimeCallGenerator(name, soughtFuncType);
   return genElementalCall(runtimeCallGenerator, name, *resultType, args,
-                          /* outline */ true);
+                          /*outline=*/outlineAllIntrinsics);
 }
 
 mlir::Value
@@ -1730,29 +1956,58 @@ fir::ExtendedValue IntrinsicLibrary::outlineInExtendedWrapper(
 IntrinsicLibrary::RuntimeCallGenerator
 IntrinsicLibrary::getRuntimeCallGenerator(llvm::StringRef name,
                                           mlir::FunctionType soughtFuncType) {
-  mlir::func::FuncOp funcOp =
-      getRuntimeFunction(loc, builder, name, soughtFuncType);
-  if (!funcOp) {
+  mlir::func::FuncOp funcOp;
+  mlir::FunctionType actualFuncType;
+  const MathOperation *mathOp = nullptr;
+  if (!lowerEarlyToLibCall) {
+    // Look for a dedicated math operation generator, which
+    // normally produces a single MLIR operation implementing
+    // the math operation.
+    // If not found fall back to a runtime function lookup.
+    const MathOperation *bestNearMatch = nullptr;
+    FunctionDistance bestMatchDistance;
+    mathOp = searchMathOperation(builder, name, soughtFuncType, &bestNearMatch,
+                                 bestMatchDistance);
+    if (!mathOp && bestNearMatch) {
+      // Use the best near match, optionally issuing an error,
+      // if types conversions cause precision loss.
+      checkPrecisionLoss(name, soughtFuncType, bestMatchDistance, loc);
+      mathOp = bestNearMatch;
+    }
+    if (mathOp)
+      actualFuncType = mathOp->typeGenerator(builder.getContext());
+  }
+  if (!mathOp)
+    if ((funcOp = getRuntimeFunction(loc, builder, name, soughtFuncType)))
+      actualFuncType = funcOp.getFunctionType();
+
+  if (!mathOp && !funcOp) {
     std::string nameAndType;
     llvm::raw_string_ostream sstream(nameAndType);
     sstream << name << "\nrequested type: " << soughtFuncType;
     crashOnMissingIntrinsic(loc, nameAndType);
   }
 
-  mlir::FunctionType actualFuncType = funcOp.getFunctionType();
   assert(actualFuncType.getNumResults() == soughtFuncType.getNumResults() &&
          actualFuncType.getNumInputs() == soughtFuncType.getNumInputs() &&
          actualFuncType.getNumResults() == 1 && "Bad intrinsic match");
 
-  return [funcOp, actualFuncType,
+  return [funcOp, actualFuncType, mathOp,
           soughtFuncType](fir::FirOpBuilder &builder, mlir::Location loc,
                           llvm::ArrayRef<mlir::Value> args) {
     llvm::SmallVector<mlir::Value> convertedArguments;
     for (auto [fst, snd] : llvm::zip(actualFuncType.getInputs(), args))
       convertedArguments.push_back(builder.createConvert(loc, fst, snd));
-    auto call = builder.create<fir::CallOp>(loc, funcOp, convertedArguments);
+    mlir::Value result;
+    // Use math operation generator, if available.
+    if (mathOp)
+      result = mathOp->funcGenerator(builder, loc, mathOp->runtimeFunc,
+                                     actualFuncType, convertedArguments);
+    else
+      result = builder.create<fir::CallOp>(loc, funcOp, convertedArguments)
+                   .getResult(0);
     mlir::Type soughtType = soughtFuncType.getResult(0);
-    return builder.createConvert(loc, soughtType, call.getResult(0));
+    return builder.createConvert(loc, soughtType, result);
   };
 }
 
@@ -1918,7 +2173,7 @@ mlir::Value IntrinsicLibrary::genAimag(mlir::Type resultType,
                                        llvm::ArrayRef<mlir::Value> args) {
   assert(args.size() == 1);
   return fir::factory::Complex{builder, loc}.extractComplexPart(
-      args[0], true /* isImagPart */);
+      args[0], /*isImagPart=*/true);
 }
 
 // AINT
@@ -4032,6 +4287,13 @@ mlir::Value Fortran::lower::genMin(fir::FirOpBuilder &builder,
 mlir::Value Fortran::lower::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 and (!lowerEarlyToLibCall).
+  //       One option is to generate internal function with inlined
+  //       implementation and mark it 'strictfp'.
+  //       Another option is to implement it in Fortran runtime library
+  //       (just like matmul).
   return IntrinsicLibrary{builder, loc}.genRuntimeCall("pow", type, {x, y});
 }
 

diff  --git a/flang/lib/Optimizer/CodeGen/CMakeLists.txt b/flang/lib/Optimizer/CodeGen/CMakeLists.txt
index e9e4ca29f4eb6..e4bc0d8bb680d 100644
--- a/flang/lib/Optimizer/CodeGen/CMakeLists.txt
+++ b/flang/lib/Optimizer/CodeGen/CMakeLists.txt
@@ -17,6 +17,8 @@ add_flang_library(FIRCodeGen
   FIRBuilder
   FIRDialect
   FIRSupport
+  MLIRMathToLLVM
+  MLIRMathToLibm
   MLIROpenMPToLLVM
   MLIRLLVMToLLVMIRTranslation
   MLIRTargetLLVMIRExport

diff  --git a/flang/lib/Optimizer/CodeGen/CodeGen.cpp b/flang/lib/Optimizer/CodeGen/CodeGen.cpp
index a451a5da1dcfa..2a5f126b684b2 100644
--- a/flang/lib/Optimizer/CodeGen/CodeGen.cpp
+++ b/flang/lib/Optimizer/CodeGen/CodeGen.cpp
@@ -23,6 +23,8 @@
 #include "mlir/Conversion/ControlFlowToLLVM/ControlFlowToLLVM.h"
 #include "mlir/Conversion/FuncToLLVM/ConvertFuncToLLVM.h"
 #include "mlir/Conversion/LLVMCommon/Pattern.h"
+#include "mlir/Conversion/MathToLLVM/MathToLLVM.h"
+#include "mlir/Conversion/MathToLibm/MathToLibm.h"
 #include "mlir/Conversion/OpenMPToLLVM/ConvertOpenMPToLLVM.h"
 #include "mlir/IR/BuiltinTypes.h"
 #include "mlir/IR/Matchers.h"
@@ -3380,6 +3382,10 @@ class FIRToLLVMLowering : public fir::FIRToLLVMLoweringBase<FIRToLLVMLowering> {
                                                             pattern);
     mlir::cf::populateControlFlowToLLVMConversionPatterns(typeConverter,
                                                           pattern);
+    // Convert math-like dialect operations, which can be produced
+    // when late math lowering mode is used, into llvm dialect.
+    mlir::populateMathToLLVMConversionPatterns(typeConverter, pattern);
+    mlir::populateMathToLibmConversionPatterns(pattern, /*benefit=*/0);
     mlir::ConversionTarget target{*context};
     target.addLegalDialect<mlir::LLVM::LLVMDialect>();
     // The OpenMP dialect is legal for Operations without regions, for those

diff  --git a/flang/test/Intrinsics/late-math-codegen.fir b/flang/test/Intrinsics/late-math-codegen.fir
new file mode 100644
index 0000000000000..4aaf6596141ff
--- /dev/null
+++ b/flang/test/Intrinsics/late-math-codegen.fir
@@ -0,0 +1,1590 @@
+// RUN: split-file %s %t
+// TODO: verify that Fast-Math Flags and 'strictfp' are properly set.
+
+//--- abs_fast.fir
+// RUN: fir-opt %t/abs_fast.fir --fir-to-llvm-ir="target=x86_64-unknown-linux-gnu" | FileCheck %t/abs_fast.fir
+// CHECK: @_QPtest_real4
+// CHECK: {{%[A-Za-z0-9._]+}} = "llvm.intr.fabs"({{%[A-Za-z0-9._]+}}) : (f32) -> f32
+
+// CHECK: @_QPtest_real8
+// CHECK: {{%[A-Za-z0-9._]+}} = "llvm.intr.fabs"({{%[A-Za-z0-9._]+}}) : (f64) -> f64
+
+// CHECK: @_QPtest_complex4
+// CHECK: {{%[A-Za-z0-9._]+}} = llvm.call @hypotf({{%[A-Za-z0-9._]+}}, {{%[A-Za-z0-9._]+}}) : (f32, f32) -> f32
+
+// CHECK: @_QPtest_complex8
+// CHECK: {{%[A-Za-z0-9._]+}} = llvm.call @hypot({{%[A-Za-z0-9._]+}}, {{%[A-Za-z0-9._]+}}) : (f64, f64) -> f64
+
+func.func @_QPtest_real4(%arg0: !fir.ref<f32> {fir.bindc_name = "x"}) -> f32 {
+  %0 = fir.alloca f32 {bindc_name = "test_real4", uniq_name = "_QFtest_real4Etest_real4"}
+  %1 = fir.load %arg0 : !fir.ref<f32>
+  %2 = math.abs %1 : f32
+  fir.store %2 to %0 : !fir.ref<f32>
+  %3 = fir.load %0 : !fir.ref<f32>
+  return %3 : f32
+}
+func.func @_QPtest_real8(%arg0: !fir.ref<f64> {fir.bindc_name = "x"}) -> f64 {
+  %0 = fir.alloca f64 {bindc_name = "test_real8", uniq_name = "_QFtest_real8Etest_real8"}
+  %1 = fir.load %arg0 : !fir.ref<f64>
+  %2 = math.abs %1 : f64
+  fir.store %2 to %0 : !fir.ref<f64>
+  %3 = fir.load %0 : !fir.ref<f64>
+  return %3 : f64
+}
+func.func @_QPtest_complex4(%arg0: !fir.ref<!fir.complex<4>> {fir.bindc_name = "c"}) -> !fir.complex<4> {
+  %0 = fir.alloca !fir.complex<4> {bindc_name = "test_complex4", uniq_name = "_QFtest_complex4Etest_complex4"}
+  %1 = fir.load %arg0 : !fir.ref<!fir.complex<4>>
+  %2 = fir.extract_value %1, [0 : index] : (!fir.complex<4>) -> f32
+  %3 = fir.extract_value %1, [1 : index] : (!fir.complex<4>) -> f32
+  %4 = fir.call @hypotf(%2, %3) : (f32, f32) -> f32
+  %cst = arith.constant 0.000000e+00 : f32
+  %5 = fir.undefined !fir.complex<4>
+  %6 = fir.insert_value %5, %4, [0 : index] : (!fir.complex<4>, f32) -> !fir.complex<4>
+  %7 = fir.insert_value %6, %cst, [1 : index] : (!fir.complex<4>, f32) -> !fir.complex<4>
+  fir.store %7 to %0 : !fir.ref<!fir.complex<4>>
+  %8 = fir.load %0 : !fir.ref<!fir.complex<4>>
+  return %8 : !fir.complex<4>
+}
+func.func @_QPtest_complex8(%arg0: !fir.ref<!fir.complex<8>> {fir.bindc_name = "c"}) -> !fir.complex<8> {
+  %0 = fir.alloca !fir.complex<8> {bindc_name = "test_complex8", uniq_name = "_QFtest_complex8Etest_complex8"}
+  %1 = fir.load %arg0 : !fir.ref<!fir.complex<8>>
+  %2 = fir.extract_value %1, [0 : index] : (!fir.complex<8>) -> f64
+  %3 = fir.extract_value %1, [1 : index] : (!fir.complex<8>) -> f64
+  %4 = fir.call @hypot(%2, %3) : (f64, f64) -> f64
+  %cst = arith.constant 0.000000e+00 : f64
+  %5 = fir.undefined !fir.complex<8>
+  %6 = fir.insert_value %5, %4, [0 : index] : (!fir.complex<8>, f64) -> !fir.complex<8>
+  %7 = fir.insert_value %6, %cst, [1 : index] : (!fir.complex<8>, f64) -> !fir.complex<8>
+  fir.store %7 to %0 : !fir.ref<!fir.complex<8>>
+  %8 = fir.load %0 : !fir.ref<!fir.complex<8>>
+  return %8 : !fir.complex<8>
+}
+func.func private @hypotf(f32, f32) -> f32
+func.func private @hypot(f64, f64) -> f64
+
+//--- abs_relaxed.fir
+// RUN: fir-opt %t/abs_relaxed.fir --fir-to-llvm-ir="target=x86_64-unknown-linux-gnu" | FileCheck %t/abs_relaxed.fir
+// CHECK: @_QPtest_real4
+// CHECK: {{%[A-Za-z0-9._]+}} = "llvm.intr.fabs"({{%[A-Za-z0-9._]+}}) : (f32) -> f32
+
+// CHECK: @_QPtest_real8
+// CHECK: {{%[A-Za-z0-9._]+}} = "llvm.intr.fabs"({{%[A-Za-z0-9._]+}}) : (f64) -> f64
+
+// CHECK: @_QPtest_complex4
+// CHECK: {{%[A-Za-z0-9._]+}} = llvm.call @hypotf({{%[A-Za-z0-9._]+}}, {{%[A-Za-z0-9._]+}}) : (f32, f32) -> f32
+
+// CHECK: @_QPtest_complex8
+// CHECK: {{%[A-Za-z0-9._]+}} = llvm.call @hypot({{%[A-Za-z0-9._]+}}, {{%[A-Za-z0-9._]+}}) : (f64, f64) -> f64
+
+func.func @_QPtest_real4(%arg0: !fir.ref<f32> {fir.bindc_name = "x"}) -> f32 {
+  %0 = fir.alloca f32 {bindc_name = "test_real4", uniq_name = "_QFtest_real4Etest_real4"}
+  %1 = fir.load %arg0 : !fir.ref<f32>
+  %2 = math.abs %1 : f32
+  fir.store %2 to %0 : !fir.ref<f32>
+  %3 = fir.load %0 : !fir.ref<f32>
+  return %3 : f32
+}
+func.func @_QPtest_real8(%arg0: !fir.ref<f64> {fir.bindc_name = "x"}) -> f64 {
+  %0 = fir.alloca f64 {bindc_name = "test_real8", uniq_name = "_QFtest_real8Etest_real8"}
+  %1 = fir.load %arg0 : !fir.ref<f64>
+  %2 = math.abs %1 : f64
+  fir.store %2 to %0 : !fir.ref<f64>
+  %3 = fir.load %0 : !fir.ref<f64>
+  return %3 : f64
+}
+func.func @_QPtest_complex4(%arg0: !fir.ref<!fir.complex<4>> {fir.bindc_name = "c"}) -> !fir.complex<4> {
+  %0 = fir.alloca !fir.complex<4> {bindc_name = "test_complex4", uniq_name = "_QFtest_complex4Etest_complex4"}
+  %1 = fir.load %arg0 : !fir.ref<!fir.complex<4>>
+  %2 = fir.extract_value %1, [0 : index] : (!fir.complex<4>) -> f32
+  %3 = fir.extract_value %1, [1 : index] : (!fir.complex<4>) -> f32
+  %4 = fir.call @hypotf(%2, %3) : (f32, f32) -> f32
+  %cst = arith.constant 0.000000e+00 : f32
+  %5 = fir.undefined !fir.complex<4>
+  %6 = fir.insert_value %5, %4, [0 : index] : (!fir.complex<4>, f32) -> !fir.complex<4>
+  %7 = fir.insert_value %6, %cst, [1 : index] : (!fir.complex<4>, f32) -> !fir.complex<4>
+  fir.store %7 to %0 : !fir.ref<!fir.complex<4>>
+  %8 = fir.load %0 : !fir.ref<!fir.complex<4>>
+  return %8 : !fir.complex<4>
+}
+func.func @_QPtest_complex8(%arg0: !fir.ref<!fir.complex<8>> {fir.bindc_name = "c"}) -> !fir.complex<8> {
+  %0 = fir.alloca !fir.complex<8> {bindc_name = "test_complex8", uniq_name = "_QFtest_complex8Etest_complex8"}
+  %1 = fir.load %arg0 : !fir.ref<!fir.complex<8>>
+  %2 = fir.extract_value %1, [0 : index] : (!fir.complex<8>) -> f64
+  %3 = fir.extract_value %1, [1 : index] : (!fir.complex<8>) -> f64
+  %4 = fir.call @hypot(%2, %3) : (f64, f64) -> f64
+  %cst = arith.constant 0.000000e+00 : f64
+  %5 = fir.undefined !fir.complex<8>
+  %6 = fir.insert_value %5, %4, [0 : index] : (!fir.complex<8>, f64) -> !fir.complex<8>
+  %7 = fir.insert_value %6, %cst, [1 : index] : (!fir.complex<8>, f64) -> !fir.complex<8>
+  fir.store %7 to %0 : !fir.ref<!fir.complex<8>>
+  %8 = fir.load %0 : !fir.ref<!fir.complex<8>>
+  return %8 : !fir.complex<8>
+}
+func.func private @hypotf(f32, f32) -> f32
+func.func private @hypot(f64, f64) -> f64
+
+//--- abs_precise.fir
+// RUN: fir-opt %t/abs_precise.fir --fir-to-llvm-ir="target=x86_64-unknown-linux-gnu" | FileCheck %t/abs_precise.fir
+// CHECK: @_QPtest_real4
+// CHECK: {{%[A-Za-z0-9._]+}} = llvm.call @fabsf({{%[A-Za-z0-9._]+}}) : (f32) -> f32
+
+// CHECK: @_QPtest_real8
+// CHECK: {{%[A-Za-z0-9._]+}} = llvm.call @fabs({{%[A-Za-z0-9._]+}}) : (f64) -> f64
+
+// CHECK: @_QPtest_complex4
+// CHECK: {{%[A-Za-z0-9._]+}} = llvm.call @hypotf({{%[A-Za-z0-9._]+}}, {{%[A-Za-z0-9._]+}}) : (f32, f32) -> f32
+
+// CHECK: @_QPtest_complex8
+// CHECK: {{%[A-Za-z0-9._]+}} = llvm.call @hypot({{%[A-Za-z0-9._]+}}, {{%[A-Za-z0-9._]+}}) : (f64, f64) -> f64
+
+func.func @_QPtest_real4(%arg0: !fir.ref<f32> {fir.bindc_name = "x"}) -> f32 {
+  %0 = fir.alloca f32 {bindc_name = "test_real4", uniq_name = "_QFtest_real4Etest_real4"}
+  %1 = fir.load %arg0 : !fir.ref<f32>
+  %2 = fir.call @fabsf(%1) : (f32) -> f32
+  fir.store %2 to %0 : !fir.ref<f32>
+  %3 = fir.load %0 : !fir.ref<f32>
+  return %3 : f32
+}
+func.func @_QPtest_real8(%arg0: !fir.ref<f64> {fir.bindc_name = "x"}) -> f64 {
+  %0 = fir.alloca f64 {bindc_name = "test_real8", uniq_name = "_QFtest_real8Etest_real8"}
+  %1 = fir.load %arg0 : !fir.ref<f64>
+  %2 = fir.call @fabs(%1) : (f64) -> f64
+  fir.store %2 to %0 : !fir.ref<f64>
+  %3 = fir.load %0 : !fir.ref<f64>
+  return %3 : f64
+}
+func.func @_QPtest_complex4(%arg0: !fir.ref<!fir.complex<4>> {fir.bindc_name = "c"}) -> !fir.complex<4> {
+  %0 = fir.alloca !fir.complex<4> {bindc_name = "test_complex4", uniq_name = "_QFtest_complex4Etest_complex4"}
+  %1 = fir.load %arg0 : !fir.ref<!fir.complex<4>>
+  %2 = fir.extract_value %1, [0 : index] : (!fir.complex<4>) -> f32
+  %3 = fir.extract_value %1, [1 : index] : (!fir.complex<4>) -> f32
+  %4 = fir.call @hypotf(%2, %3) : (f32, f32) -> f32
+  %cst = arith.constant 0.000000e+00 : f32
+  %5 = fir.undefined !fir.complex<4>
+  %6 = fir.insert_value %5, %4, [0 : index] : (!fir.complex<4>, f32) -> !fir.complex<4>
+  %7 = fir.insert_value %6, %cst, [1 : index] : (!fir.complex<4>, f32) -> !fir.complex<4>
+  fir.store %7 to %0 : !fir.ref<!fir.complex<4>>
+  %8 = fir.load %0 : !fir.ref<!fir.complex<4>>
+  return %8 : !fir.complex<4>
+}
+func.func @_QPtest_complex8(%arg0: !fir.ref<!fir.complex<8>> {fir.bindc_name = "c"}) -> !fir.complex<8> {
+  %0 = fir.alloca !fir.complex<8> {bindc_name = "test_complex8", uniq_name = "_QFtest_complex8Etest_complex8"}
+  %1 = fir.load %arg0 : !fir.ref<!fir.complex<8>>
+  %2 = fir.extract_value %1, [0 : index] : (!fir.complex<8>) -> f64
+  %3 = fir.extract_value %1, [1 : index] : (!fir.complex<8>) -> f64
+  %4 = fir.call @hypot(%2, %3) : (f64, f64) -> f64
+  %cst = arith.constant 0.000000e+00 : f64
+  %5 = fir.undefined !fir.complex<8>
+  %6 = fir.insert_value %5, %4, [0 : index] : (!fir.complex<8>, f64) -> !fir.complex<8>
+  %7 = fir.insert_value %6, %cst, [1 : index] : (!fir.complex<8>, f64) -> !fir.complex<8>
+  fir.store %7 to %0 : !fir.ref<!fir.complex<8>>
+  %8 = fir.load %0 : !fir.ref<!fir.complex<8>>
+  return %8 : !fir.complex<8>
+}
+func.func private @fabsf(f32) -> f32
+func.func private @fabs(f64) -> f64
+func.func private @hypotf(f32, f32) -> f32
+func.func private @hypot(f64, f64) -> f64
+
+//--- aint_fast.fir
+// RUN: fir-opt %t/aint_fast.fir --fir-to-llvm-ir="target=x86_64-unknown-linux-gnu" | FileCheck %t/aint_fast.fir
+// CHECK: @_QPtest_real4
+// CHECK: {{%[A-Za-z0-9._]+}} = llvm.call @llvm.trunc.f32({{%[A-Za-z0-9._]+}}) : (f32) -> f32
+
+// CHECK: @_QPtest_real8
+// CHECK: {{%[A-Za-z0-9._]+}} = llvm.call @llvm.trunc.f64({{%[A-Za-z0-9._]+}}) : (f64) -> f64
+
+func.func @_QPtest_real4(%arg0: !fir.ref<f32> {fir.bindc_name = "x"}) -> f32 {
+  %0 = fir.alloca f32 {bindc_name = "test_real4", uniq_name = "_QFtest_real4Etest_real4"}
+  %1 = fir.load %arg0 : !fir.ref<f32>
+  %2 = fir.call @llvm.trunc.f32(%1) : (f32) -> f32
+  fir.store %2 to %0 : !fir.ref<f32>
+  %3 = fir.load %0 : !fir.ref<f32>
+  return %3 : f32
+}
+func.func @_QPtest_real8(%arg0: !fir.ref<f64> {fir.bindc_name = "x"}) -> f64 {
+  %0 = fir.alloca f64 {bindc_name = "test_real8", uniq_name = "_QFtest_real8Etest_real8"}
+  %1 = fir.load %arg0 : !fir.ref<f64>
+  %2 = fir.call @llvm.trunc.f64(%1) : (f64) -> f64
+  fir.store %2 to %0 : !fir.ref<f64>
+  %3 = fir.load %0 : !fir.ref<f64>
+  return %3 : f64
+}
+func.func private @llvm.trunc.f32(f32) -> f32
+func.func private @llvm.trunc.f64(f64) -> f64
+
+//--- aint_relaxed.fir
+// RUN: fir-opt %t/aint_relaxed.fir --fir-to-llvm-ir="target=x86_64-unknown-linux-gnu" | FileCheck %t/aint_relaxed.fir
+// CHECK: @_QPtest_real4
+// CHECK: {{%[A-Za-z0-9._]+}} = llvm.call @llvm.trunc.f32({{%[A-Za-z0-9._]+}}) : (f32) -> f32
+
+// CHECK: @_QPtest_real8
+// CHECK: {{%[A-Za-z0-9._]+}} = llvm.call @llvm.trunc.f64({{%[A-Za-z0-9._]+}}) : (f64) -> f64
+
+func.func @_QPtest_real4(%arg0: !fir.ref<f32> {fir.bindc_name = "x"}) -> f32 {
+  %0 = fir.alloca f32 {bindc_name = "test_real4", uniq_name = "_QFtest_real4Etest_real4"}
+  %1 = fir.load %arg0 : !fir.ref<f32>
+  %2 = fir.call @llvm.trunc.f32(%1) : (f32) -> f32
+  fir.store %2 to %0 : !fir.ref<f32>
+  %3 = fir.load %0 : !fir.ref<f32>
+  return %3 : f32
+}
+func.func @_QPtest_real8(%arg0: !fir.ref<f64> {fir.bindc_name = "x"}) -> f64 {
+  %0 = fir.alloca f64 {bindc_name = "test_real8", uniq_name = "_QFtest_real8Etest_real8"}
+  %1 = fir.load %arg0 : !fir.ref<f64>
+  %2 = fir.call @llvm.trunc.f64(%1) : (f64) -> f64
+  fir.store %2 to %0 : !fir.ref<f64>
+  %3 = fir.load %0 : !fir.ref<f64>
+  return %3 : f64
+}
+func.func private @llvm.trunc.f32(f32) -> f32
+func.func private @llvm.trunc.f64(f64) -> f64
+
+//--- aint_precise.fir
+// RUN: fir-opt %t/aint_precise.fir --fir-to-llvm-ir="target=x86_64-unknown-linux-gnu" | FileCheck %t/aint_precise.fir
+// CHECK: @_QPtest_real4
+// CHECK: {{%[A-Za-z0-9._]+}} = llvm.call @llvm.trunc.f32({{%[A-Za-z0-9._]+}}) : (f32) -> f32
+
+// CHECK: @_QPtest_real8
+// CHECK: {{%[A-Za-z0-9._]+}} = llvm.call @llvm.trunc.f64({{%[A-Za-z0-9._]+}}) : (f64) -> f64
+
+func.func @_QPtest_real4(%arg0: !fir.ref<f32> {fir.bindc_name = "x"}) -> f32 {
+  %0 = fir.alloca f32 {bindc_name = "test_real4", uniq_name = "_QFtest_real4Etest_real4"}
+  %1 = fir.load %arg0 : !fir.ref<f32>
+  %2 = fir.call @llvm.trunc.f32(%1) : (f32) -> f32
+  fir.store %2 to %0 : !fir.ref<f32>
+  %3 = fir.load %0 : !fir.ref<f32>
+  return %3 : f32
+}
+func.func @_QPtest_real8(%arg0: !fir.ref<f64> {fir.bindc_name = "x"}) -> f64 {
+  %0 = fir.alloca f64 {bindc_name = "test_real8", uniq_name = "_QFtest_real8Etest_real8"}
+  %1 = fir.load %arg0 : !fir.ref<f64>
+  %2 = fir.call @llvm.trunc.f64(%1) : (f64) -> f64
+  fir.store %2 to %0 : !fir.ref<f64>
+  %3 = fir.load %0 : !fir.ref<f64>
+  return %3 : f64
+}
+func.func private @llvm.trunc.f32(f32) -> f32
+func.func private @llvm.trunc.f64(f64) -> f64
+
+//--- anint_fast.fir
+// RUN: fir-opt %t/anint_fast.fir --fir-to-llvm-ir="target=x86_64-unknown-linux-gnu" | FileCheck %t/anint_fast.fir
+// CHECK: @_QPtest_real4
+// CHECK: {{%[A-Za-z0-9._]+}} = "llvm.intr.round"({{%[A-Za-z0-9._]+}}) : (f32) -> f32
+
+// CHECK: @_QPtest_real8
+// CHECK: {{%[A-Za-z0-9._]+}} = "llvm.intr.round"({{%[A-Za-z0-9._]+}}) : (f64) -> f64
+
+func.func @_QPtest_real4(%arg0: !fir.ref<f32> {fir.bindc_name = "x"}) -> f32 {
+  %0 = fir.alloca f32 {bindc_name = "test_real4", uniq_name = "_QFtest_real4Etest_real4"}
+  %1 = fir.load %arg0 : !fir.ref<f32>
+  %2 = "llvm.intr.round"(%1) : (f32) -> f32
+  fir.store %2 to %0 : !fir.ref<f32>
+  %3 = fir.load %0 : !fir.ref<f32>
+  return %3 : f32
+}
+func.func @_QPtest_real8(%arg0: !fir.ref<f64> {fir.bindc_name = "x"}) -> f64 {
+  %0 = fir.alloca f64 {bindc_name = "test_real8", uniq_name = "_QFtest_real8Etest_real8"}
+  %1 = fir.load %arg0 : !fir.ref<f64>
+  %2 = "llvm.intr.round"(%1) : (f64) -> f64
+  fir.store %2 to %0 : !fir.ref<f64>
+  %3 = fir.load %0 : !fir.ref<f64>
+  return %3 : f64
+}
+
+//--- anint_relaxed.fir
+// RUN: fir-opt %t/anint_relaxed.fir --fir-to-llvm-ir="target=x86_64-unknown-linux-gnu" | FileCheck %t/anint_relaxed.fir
+// CHECK: @_QPtest_real4
+// CHECK: {{%[A-Za-z0-9._]+}} = "llvm.intr.round"({{%[A-Za-z0-9._]+}}) : (f32) -> f32
+
+// CHECK: @_QPtest_real8
+// CHECK: {{%[A-Za-z0-9._]+}} = "llvm.intr.round"({{%[A-Za-z0-9._]+}}) : (f64) -> f64
+
+func.func @_QPtest_real4(%arg0: !fir.ref<f32> {fir.bindc_name = "x"}) -> f32 {
+  %0 = fir.alloca f32 {bindc_name = "test_real4", uniq_name = "_QFtest_real4Etest_real4"}
+  %1 = fir.load %arg0 : !fir.ref<f32>
+  %2 = "llvm.intr.round"(%1) : (f32) -> f32
+  fir.store %2 to %0 : !fir.ref<f32>
+  %3 = fir.load %0 : !fir.ref<f32>
+  return %3 : f32
+}
+func.func @_QPtest_real8(%arg0: !fir.ref<f64> {fir.bindc_name = "x"}) -> f64 {
+  %0 = fir.alloca f64 {bindc_name = "test_real8", uniq_name = "_QFtest_real8Etest_real8"}
+  %1 = fir.load %arg0 : !fir.ref<f64>
+  %2 = "llvm.intr.round"(%1) : (f64) -> f64
+  fir.store %2 to %0 : !fir.ref<f64>
+  %3 = fir.load %0 : !fir.ref<f64>
+  return %3 : f64
+}
+
+//--- anint_precise.fir
+// RUN: fir-opt %t/anint_precise.fir --fir-to-llvm-ir="target=x86_64-unknown-linux-gnu" | FileCheck %t/anint_precise.fir
+// CHECK: @_QPtest_real4
+// CHECK: {{%[A-Za-z0-9._]+}} = llvm.call @llvm.round.f32({{%[A-Za-z0-9._]+}}) : (f32) -> f32
+
+// CHECK: @_QPtest_real8
+// CHECK: {{%[A-Za-z0-9._]+}} = llvm.call @llvm.round.f64({{%[A-Za-z0-9._]+}}) : (f64) -> f64
+
+func.func @_QPtest_real4(%arg0: !fir.ref<f32> {fir.bindc_name = "x"}) -> f32 {
+  %0 = fir.alloca f32 {bindc_name = "test_real4", uniq_name = "_QFtest_real4Etest_real4"}
+  %1 = fir.load %arg0 : !fir.ref<f32>
+  %2 = fir.call @llvm.round.f32(%1) : (f32) -> f32
+  fir.store %2 to %0 : !fir.ref<f32>
+  %3 = fir.load %0 : !fir.ref<f32>
+  return %3 : f32
+}
+func.func @_QPtest_real8(%arg0: !fir.ref<f64> {fir.bindc_name = "x"}) -> f64 {
+  %0 = fir.alloca f64 {bindc_name = "test_real8", uniq_name = "_QFtest_real8Etest_real8"}
+  %1 = fir.load %arg0 : !fir.ref<f64>
+  %2 = fir.call @llvm.round.f64(%1) : (f64) -> f64
+  fir.store %2 to %0 : !fir.ref<f64>
+  %3 = fir.load %0 : !fir.ref<f64>
+  return %3 : f64
+}
+func.func private @llvm.round.f32(f32) -> f32
+func.func private @llvm.round.f64(f64) -> f64
+
+//--- atan_fast.fir
+// RUN: fir-opt %t/atan_fast.fir --fir-to-llvm-ir="target=x86_64-unknown-linux-gnu" | FileCheck %t/atan_fast.fir
+// CHECK: @_QPtest_real4
+// CHECK: {{%[A-Za-z0-9._]+}} = llvm.call @atanf({{%[A-Za-z0-9._]+}}) : (f32) -> f32
+
+// CHECK: @_QPtest_real8
+// CHECK: {{%[A-Za-z0-9._]+}} = llvm.call @atan({{%[A-Za-z0-9._]+}}) : (f64) -> f64
+
+func.func @_QPtest_real4(%arg0: !fir.ref<f32> {fir.bindc_name = "x"}) -> f32 {
+  %0 = fir.alloca f32 {bindc_name = "test_real4", uniq_name = "_QFtest_real4Etest_real4"}
+  %1 = fir.load %arg0 : !fir.ref<f32>
+  %2 = math.atan %1 : f32
+  fir.store %2 to %0 : !fir.ref<f32>
+  %3 = fir.load %0 : !fir.ref<f32>
+  return %3 : f32
+}
+func.func @_QPtest_real8(%arg0: !fir.ref<f64> {fir.bindc_name = "x"}) -> f64 {
+  %0 = fir.alloca f64 {bindc_name = "test_real8", uniq_name = "_QFtest_real8Etest_real8"}
+  %1 = fir.load %arg0 : !fir.ref<f64>
+  %2 = math.atan %1 : f64
+  fir.store %2 to %0 : !fir.ref<f64>
+  %3 = fir.load %0 : !fir.ref<f64>
+  return %3 : f64
+}
+
+//--- atan_relaxed.fir
+// RUN: fir-opt %t/atan_relaxed.fir --fir-to-llvm-ir="target=x86_64-unknown-linux-gnu" | FileCheck %t/atan_relaxed.fir
+// CHECK: @_QPtest_real4
+// CHECK: {{%[A-Za-z0-9._]+}} = llvm.call @atanf({{%[A-Za-z0-9._]+}}) : (f32) -> f32
+
+// CHECK: @_QPtest_real8
+// CHECK: {{%[A-Za-z0-9._]+}} = llvm.call @atan({{%[A-Za-z0-9._]+}}) : (f64) -> f64
+
+func.func @_QPtest_real4(%arg0: !fir.ref<f32> {fir.bindc_name = "x"}) -> f32 {
+  %0 = fir.alloca f32 {bindc_name = "test_real4", uniq_name = "_QFtest_real4Etest_real4"}
+  %1 = fir.load %arg0 : !fir.ref<f32>
+  %2 = math.atan %1 : f32
+  fir.store %2 to %0 : !fir.ref<f32>
+  %3 = fir.load %0 : !fir.ref<f32>
+  return %3 : f32
+}
+func.func @_QPtest_real8(%arg0: !fir.ref<f64> {fir.bindc_name = "x"}) -> f64 {
+  %0 = fir.alloca f64 {bindc_name = "test_real8", uniq_name = "_QFtest_real8Etest_real8"}
+  %1 = fir.load %arg0 : !fir.ref<f64>
+  %2 = math.atan %1 : f64
+  fir.store %2 to %0 : !fir.ref<f64>
+  %3 = fir.load %0 : !fir.ref<f64>
+  return %3 : f64
+}
+
+//--- atan_precise.fir
+// RUN: fir-opt %t/atan_precise.fir --fir-to-llvm-ir="target=x86_64-unknown-linux-gnu" | FileCheck %t/atan_precise.fir
+// CHECK: @_QPtest_real4
+// CHECK: {{%[A-Za-z0-9._]+}} = llvm.call @atanf({{%[A-Za-z0-9._]+}}) : (f32) -> f32
+
+// CHECK: @_QPtest_real8
+// CHECK: {{%[A-Za-z0-9._]+}} = llvm.call @atan({{%[A-Za-z0-9._]+}}) : (f64) -> f64
+
+func.func @_QPtest_real4(%arg0: !fir.ref<f32> {fir.bindc_name = "x"}) -> f32 {
+  %0 = fir.alloca f32 {bindc_name = "test_real4", uniq_name = "_QFtest_real4Etest_real4"}
+  %1 = fir.load %arg0 : !fir.ref<f32>
+  %2 = fir.call @atanf(%1) : (f32) -> f32
+  fir.store %2 to %0 : !fir.ref<f32>
+  %3 = fir.load %0 : !fir.ref<f32>
+  return %3 : f32
+}
+func.func @_QPtest_real8(%arg0: !fir.ref<f64> {fir.bindc_name = "x"}) -> f64 {
+  %0 = fir.alloca f64 {bindc_name = "test_real8", uniq_name = "_QFtest_real8Etest_real8"}
+  %1 = fir.load %arg0 : !fir.ref<f64>
+  %2 = fir.call @atan(%1) : (f64) -> f64
+  fir.store %2 to %0 : !fir.ref<f64>
+  %3 = fir.load %0 : !fir.ref<f64>
+  return %3 : f64
+}
+func.func private @atanf(f32) -> f32
+func.func private @atan(f64) -> f64
+
+//--- atan2_fast.fir
+// RUN: fir-opt %t/atan2_fast.fir --fir-to-llvm-ir="target=x86_64-unknown-linux-gnu" | FileCheck %t/atan2_fast.fir
+// CHECK: @_QPtest_real4
+// CHECK: {{%[A-Za-z0-9._]+}} = llvm.call @atan2f({{%[A-Za-z0-9._]+}}, {{%[A-Za-z0-9._]+}}) : (f32, f32) -> f32
+
+// CHECK: @_QPtest_real8
+// CHECK: {{%[A-Za-z0-9._]+}} = llvm.call @atan2({{%[A-Za-z0-9._]+}}, {{%[A-Za-z0-9._]+}}) : (f64, f64) -> f64
+
+func.func @_QPtest_real4(%arg0: !fir.ref<f32> {fir.bindc_name = "x"}, %arg1: !fir.ref<f32> {fir.bindc_name = "y"}) -> f32 {
+  %0 = fir.alloca f32 {bindc_name = "test_real4", uniq_name = "_QFtest_real4Etest_real4"}
+  %1 = fir.load %arg0 : !fir.ref<f32>
+  %2 = fir.load %arg1 : !fir.ref<f32>
+  %3 = math.atan2 %1, %2 : f32
+  fir.store %3 to %0 : !fir.ref<f32>
+  %4 = fir.load %0 : !fir.ref<f32>
+  return %4 : f32
+}
+func.func @_QPtest_real8(%arg0: !fir.ref<f64> {fir.bindc_name = "x"}, %arg1: !fir.ref<f64> {fir.bindc_name = "y"}) -> f64 {
+  %0 = fir.alloca f64 {bindc_name = "test_real8", uniq_name = "_QFtest_real8Etest_real8"}
+  %1 = fir.load %arg0 : !fir.ref<f64>
+  %2 = fir.load %arg1 : !fir.ref<f64>
+  %3 = math.atan2 %1, %2 : f64
+  fir.store %3 to %0 : !fir.ref<f64>
+  %4 = fir.load %0 : !fir.ref<f64>
+  return %4 : f64
+}
+
+//--- atan2_relaxed.fir
+// RUN: fir-opt %t/atan2_relaxed.fir --fir-to-llvm-ir="target=x86_64-unknown-linux-gnu" | FileCheck %t/atan2_relaxed.fir
+// CHECK: @_QPtest_real4
+// CHECK: {{%[A-Za-z0-9._]+}} = llvm.call @atan2f({{%[A-Za-z0-9._]+}}, {{%[A-Za-z0-9._]+}}) : (f32, f32) -> f32
+
+// CHECK: @_QPtest_real8
+// CHECK: {{%[A-Za-z0-9._]+}} = llvm.call @atan2({{%[A-Za-z0-9._]+}}, {{%[A-Za-z0-9._]+}}) : (f64, f64) -> f64
+
+func.func @_QPtest_real4(%arg0: !fir.ref<f32> {fir.bindc_name = "x"}, %arg1: !fir.ref<f32> {fir.bindc_name = "y"}) -> f32 {
+  %0 = fir.alloca f32 {bindc_name = "test_real4", uniq_name = "_QFtest_real4Etest_real4"}
+  %1 = fir.load %arg0 : !fir.ref<f32>
+  %2 = fir.load %arg1 : !fir.ref<f32>
+  %3 = math.atan2 %1, %2 : f32
+  fir.store %3 to %0 : !fir.ref<f32>
+  %4 = fir.load %0 : !fir.ref<f32>
+  return %4 : f32
+}
+func.func @_QPtest_real8(%arg0: !fir.ref<f64> {fir.bindc_name = "x"}, %arg1: !fir.ref<f64> {fir.bindc_name = "y"}) -> f64 {
+  %0 = fir.alloca f64 {bindc_name = "test_real8", uniq_name = "_QFtest_real8Etest_real8"}
+  %1 = fir.load %arg0 : !fir.ref<f64>
+  %2 = fir.load %arg1 : !fir.ref<f64>
+  %3 = math.atan2 %1, %2 : f64
+  fir.store %3 to %0 : !fir.ref<f64>
+  %4 = fir.load %0 : !fir.ref<f64>
+  return %4 : f64
+}
+
+//--- atan2_precise.fir
+// RUN: fir-opt %t/atan2_precise.fir --fir-to-llvm-ir="target=x86_64-unknown-linux-gnu" | FileCheck %t/atan2_precise.fir
+// CHECK: @_QPtest_real4
+// CHECK: {{%[A-Za-z0-9._]+}} = llvm.call @atan2f({{%[A-Za-z0-9._]+}}, {{%[A-Za-z0-9._]+}}) : (f32, f32) -> f32
+
+// CHECK: @_QPtest_real8
+// CHECK: {{%[A-Za-z0-9._]+}} = llvm.call @atan2({{%[A-Za-z0-9._]+}}, {{%[A-Za-z0-9._]+}}) : (f64, f64) -> f64
+
+func.func @_QPtest_real4(%arg0: !fir.ref<f32> {fir.bindc_name = "x"}, %arg1: !fir.ref<f32> {fir.bindc_name = "y"}) -> f32 {
+  %0 = fir.alloca f32 {bindc_name = "test_real4", uniq_name = "_QFtest_real4Etest_real4"}
+  %1 = fir.load %arg0 : !fir.ref<f32>
+  %2 = fir.load %arg1 : !fir.ref<f32>
+  %3 = fir.call @atan2f(%1, %2) : (f32, f32) -> f32
+  fir.store %3 to %0 : !fir.ref<f32>
+  %4 = fir.load %0 : !fir.ref<f32>
+  return %4 : f32
+}
+func.func @_QPtest_real8(%arg0: !fir.ref<f64> {fir.bindc_name = "x"}, %arg1: !fir.ref<f64> {fir.bindc_name = "y"}) -> f64 {
+  %0 = fir.alloca f64 {bindc_name = "test_real8", uniq_name = "_QFtest_real8Etest_real8"}
+  %1 = fir.load %arg0 : !fir.ref<f64>
+  %2 = fir.load %arg1 : !fir.ref<f64>
+  %3 = fir.call @atan2(%1, %2) : (f64, f64) -> f64
+  fir.store %3 to %0 : !fir.ref<f64>
+  %4 = fir.load %0 : !fir.ref<f64>
+  return %4 : f64
+}
+func.func private @atan2f(f32, f32) -> f32
+func.func private @atan2(f64, f64) -> f64
+
+//--- ceiling_fast.fir
+// RUN: fir-opt %t/ceiling_fast.fir --fir-to-llvm-ir="target=x86_64-unknown-linux-gnu" | FileCheck %t/ceiling_fast.fir
+// CHECK: @_QPtest_real4
+// CHECK: {{%[A-Za-z0-9._]+}} = "llvm.intr.ceil"({{%[A-Za-z0-9._]+}}) : (f32) -> f32
+
+// CHECK: @_QPtest_real8
+// CHECK: {{%[A-Za-z0-9._]+}} = "llvm.intr.ceil"({{%[A-Za-z0-9._]+}}) : (f64) -> f64
+
+func.func @_QPtest_real4(%arg0: !fir.ref<f32> {fir.bindc_name = "x"}) -> f32 {
+  %0 = fir.alloca f32 {bindc_name = "test_real4", uniq_name = "_QFtest_real4Etest_real4"}
+  %1 = fir.load %arg0 : !fir.ref<f32>
+  %2 = math.ceil %1 : f32
+  %3 = fir.convert %2 : (f32) -> i32
+  %4 = fir.convert %3 : (i32) -> f32
+  fir.store %4 to %0 : !fir.ref<f32>
+  %5 = fir.load %0 : !fir.ref<f32>
+  return %5 : f32
+}
+func.func @_QPtest_real8(%arg0: !fir.ref<f64> {fir.bindc_name = "x"}) -> f64 {
+  %0 = fir.alloca f64 {bindc_name = "test_real8", uniq_name = "_QFtest_real8Etest_real8"}
+  %1 = fir.load %arg0 : !fir.ref<f64>
+  %2 = math.ceil %1 : f64
+  %3 = fir.convert %2 : (f64) -> i32
+  %4 = fir.convert %3 : (i32) -> f64
+  fir.store %4 to %0 : !fir.ref<f64>
+  %5 = fir.load %0 : !fir.ref<f64>
+  return %5 : f64
+}
+
+//--- ceiling_relaxed.fir
+// RUN: fir-opt %t/ceiling_relaxed.fir --fir-to-llvm-ir="target=x86_64-unknown-linux-gnu" | FileCheck %t/ceiling_relaxed.fir
+// CHECK: @_QPtest_real4
+// CHECK: {{%[A-Za-z0-9._]+}} = "llvm.intr.ceil"({{%[A-Za-z0-9._]+}}) : (f32) -> f32
+
+// CHECK: @_QPtest_real8
+// CHECK: {{%[A-Za-z0-9._]+}} = "llvm.intr.ceil"({{%[A-Za-z0-9._]+}}) : (f64) -> f64
+
+func.func @_QPtest_real4(%arg0: !fir.ref<f32> {fir.bindc_name = "x"}) -> f32 {
+  %0 = fir.alloca f32 {bindc_name = "test_real4", uniq_name = "_QFtest_real4Etest_real4"}
+  %1 = fir.load %arg0 : !fir.ref<f32>
+  %2 = math.ceil %1 : f32
+  %3 = fir.convert %2 : (f32) -> i32
+  %4 = fir.convert %3 : (i32) -> f32
+  fir.store %4 to %0 : !fir.ref<f32>
+  %5 = fir.load %0 : !fir.ref<f32>
+  return %5 : f32
+}
+func.func @_QPtest_real8(%arg0: !fir.ref<f64> {fir.bindc_name = "x"}) -> f64 {
+  %0 = fir.alloca f64 {bindc_name = "test_real8", uniq_name = "_QFtest_real8Etest_real8"}
+  %1 = fir.load %arg0 : !fir.ref<f64>
+  %2 = math.ceil %1 : f64
+  %3 = fir.convert %2 : (f64) -> i32
+  %4 = fir.convert %3 : (i32) -> f64
+  fir.store %4 to %0 : !fir.ref<f64>
+  %5 = fir.load %0 : !fir.ref<f64>
+  return %5 : f64
+}
+
+//--- ceiling_precise.fir
+// RUN: fir-opt %t/ceiling_precise.fir --fir-to-llvm-ir="target=x86_64-unknown-linux-gnu" | FileCheck %t/ceiling_precise.fir
+// CHECK: @_QPtest_real4
+// CHECK: {{%[A-Za-z0-9._]+}} = llvm.call @ceilf({{%[A-Za-z0-9._]+}}) : (f32) -> f32
+
+// CHECK: @_QPtest_real8
+// CHECK: {{%[A-Za-z0-9._]+}} = llvm.call @ceil({{%[A-Za-z0-9._]+}}) : (f64) -> f64
+
+func.func @_QPtest_real4(%arg0: !fir.ref<f32> {fir.bindc_name = "x"}) -> f32 {
+  %0 = fir.alloca f32 {bindc_name = "test_real4", uniq_name = "_QFtest_real4Etest_real4"}
+  %1 = fir.load %arg0 : !fir.ref<f32>
+  %2 = fir.call @ceilf(%1) : (f32) -> f32
+  %3 = fir.convert %2 : (f32) -> i32
+  %4 = fir.convert %3 : (i32) -> f32
+  fir.store %4 to %0 : !fir.ref<f32>
+  %5 = fir.load %0 : !fir.ref<f32>
+  return %5 : f32
+}
+func.func @_QPtest_real8(%arg0: !fir.ref<f64> {fir.bindc_name = "x"}) -> f64 {
+  %0 = fir.alloca f64 {bindc_name = "test_real8", uniq_name = "_QFtest_real8Etest_real8"}
+  %1 = fir.load %arg0 : !fir.ref<f64>
+  %2 = fir.call @ceil(%1) : (f64) -> f64
+  %3 = fir.convert %2 : (f64) -> i32
+  %4 = fir.convert %3 : (i32) -> f64
+  fir.store %4 to %0 : !fir.ref<f64>
+  %5 = fir.load %0 : !fir.ref<f64>
+  return %5 : f64
+}
+func.func private @ceilf(f32) -> f32
+func.func private @ceil(f64) -> f64
+
+//--- cos_fast.fir
+// RUN: fir-opt %t/cos_fast.fir --fir-to-llvm-ir="target=x86_64-unknown-linux-gnu" | FileCheck %t/cos_fast.fir
+// CHECK: @_QPtest_real4
+// CHECK: {{%[A-Za-z0-9._]+}} = "llvm.intr.cos"({{%[A-Za-z0-9._]+}}) : (f32) -> f32
+
+// CHECK: @_QPtest_real8
+// CHECK: {{%[A-Za-z0-9._]+}} = "llvm.intr.cos"({{%[A-Za-z0-9._]+}}) : (f64) -> f64
+
+func.func @_QPtest_real4(%arg0: !fir.ref<f32> {fir.bindc_name = "x"}) -> f32 {
+  %0 = fir.alloca f32 {bindc_name = "test_real4", uniq_name = "_QFtest_real4Etest_real4"}
+  %1 = fir.load %arg0 : !fir.ref<f32>
+  %2 = math.cos %1 : f32
+  fir.store %2 to %0 : !fir.ref<f32>
+  %3 = fir.load %0 : !fir.ref<f32>
+  return %3 : f32
+}
+func.func @_QPtest_real8(%arg0: !fir.ref<f64> {fir.bindc_name = "x"}) -> f64 {
+  %0 = fir.alloca f64 {bindc_name = "test_real8", uniq_name = "_QFtest_real8Etest_real8"}
+  %1 = fir.load %arg0 : !fir.ref<f64>
+  %2 = math.cos %1 : f64
+  fir.store %2 to %0 : !fir.ref<f64>
+  %3 = fir.load %0 : !fir.ref<f64>
+  return %3 : f64
+}
+
+//--- cos_relaxed.fir
+// RUN: fir-opt %t/cos_relaxed.fir --fir-to-llvm-ir="target=x86_64-unknown-linux-gnu" | FileCheck %t/cos_relaxed.fir
+// CHECK: @_QPtest_real4
+// CHECK: {{%[A-Za-z0-9._]+}} = "llvm.intr.cos"({{%[A-Za-z0-9._]+}}) : (f32) -> f32
+
+// CHECK: @_QPtest_real8
+// CHECK: {{%[A-Za-z0-9._]+}} = "llvm.intr.cos"({{%[A-Za-z0-9._]+}}) : (f64) -> f64
+
+func.func @_QPtest_real4(%arg0: !fir.ref<f32> {fir.bindc_name = "x"}) -> f32 {
+  %0 = fir.alloca f32 {bindc_name = "test_real4", uniq_name = "_QFtest_real4Etest_real4"}
+  %1 = fir.load %arg0 : !fir.ref<f32>
+  %2 = math.cos %1 : f32
+  fir.store %2 to %0 : !fir.ref<f32>
+  %3 = fir.load %0 : !fir.ref<f32>
+  return %3 : f32
+}
+func.func @_QPtest_real8(%arg0: !fir.ref<f64> {fir.bindc_name = "x"}) -> f64 {
+  %0 = fir.alloca f64 {bindc_name = "test_real8", uniq_name = "_QFtest_real8Etest_real8"}
+  %1 = fir.load %arg0 : !fir.ref<f64>
+  %2 = math.cos %1 : f64
+  fir.store %2 to %0 : !fir.ref<f64>
+  %3 = fir.load %0 : !fir.ref<f64>
+  return %3 : f64
+}
+
+//--- cos_precise.fir
+// RUN: fir-opt %t/cos_precise.fir --fir-to-llvm-ir="target=x86_64-unknown-linux-gnu" | FileCheck %t/cos_precise.fir
+// CHECK: @_QPtest_real4
+// CHECK: {{%[A-Za-z0-9._]+}} = llvm.call @cosf({{%[A-Za-z0-9._]+}}) : (f32) -> f32
+
+// CHECK: @_QPtest_real8
+// CHECK: {{%[A-Za-z0-9._]+}} = llvm.call @cos({{%[A-Za-z0-9._]+}}) : (f64) -> f64
+
+func.func @_QPtest_real4(%arg0: !fir.ref<f32> {fir.bindc_name = "x"}) -> f32 {
+  %0 = fir.alloca f32 {bindc_name = "test_real4", uniq_name = "_QFtest_real4Etest_real4"}
+  %1 = fir.load %arg0 : !fir.ref<f32>
+  %2 = fir.call @cosf(%1) : (f32) -> f32
+  fir.store %2 to %0 : !fir.ref<f32>
+  %3 = fir.load %0 : !fir.ref<f32>
+  return %3 : f32
+}
+func.func @_QPtest_real8(%arg0: !fir.ref<f64> {fir.bindc_name = "x"}) -> f64 {
+  %0 = fir.alloca f64 {bindc_name = "test_real8", uniq_name = "_QFtest_real8Etest_real8"}
+  %1 = fir.load %arg0 : !fir.ref<f64>
+  %2 = fir.call @cos(%1) : (f64) -> f64
+  fir.store %2 to %0 : !fir.ref<f64>
+  %3 = fir.load %0 : !fir.ref<f64>
+  return %3 : f64
+}
+func.func private @cosf(f32) -> f32
+func.func private @cos(f64) -> f64
+
+//--- erf_fast.fir
+// RUN: fir-opt %t/erf_fast.fir --fir-to-llvm-ir="target=x86_64-unknown-linux-gnu" | FileCheck %t/erf_fast.fir
+// CHECK: @_QPtest_real4
+// CHECK: {{%[A-Za-z0-9._]+}} = llvm.call @erff({{%[A-Za-z0-9._]+}}) : (f32) -> f32
+
+// CHECK: @_QPtest_real8
+// CHECK: {{%[A-Za-z0-9._]+}} = llvm.call @erf({{%[A-Za-z0-9._]+}}) : (f64) -> f64
+
+func.func @_QPtest_real4(%arg0: !fir.ref<f32> {fir.bindc_name = "x"}) -> f32 {
+  %0 = fir.alloca f32 {bindc_name = "test_real4", uniq_name = "_QFtest_real4Etest_real4"}
+  %1 = fir.load %arg0 : !fir.ref<f32>
+  %2 = math.erf %1 : f32
+  fir.store %2 to %0 : !fir.ref<f32>
+  %3 = fir.load %0 : !fir.ref<f32>
+  return %3 : f32
+}
+func.func @_QPtest_real8(%arg0: !fir.ref<f64> {fir.bindc_name = "x"}) -> f64 {
+  %0 = fir.alloca f64 {bindc_name = "test_real8", uniq_name = "_QFtest_real8Etest_real8"}
+  %1 = fir.load %arg0 : !fir.ref<f64>
+  %2 = math.erf %1 : f64
+  fir.store %2 to %0 : !fir.ref<f64>
+  %3 = fir.load %0 : !fir.ref<f64>
+  return %3 : f64
+}
+
+//--- erf_relaxed.fir
+// RUN: fir-opt %t/erf_relaxed.fir --fir-to-llvm-ir="target=x86_64-unknown-linux-gnu" | FileCheck %t/erf_relaxed.fir
+// CHECK: @_QPtest_real4
+// CHECK: {{%[A-Za-z0-9._]+}} = llvm.call @erff({{%[A-Za-z0-9._]+}}) : (f32) -> f32
+
+// CHECK: @_QPtest_real8
+// CHECK: {{%[A-Za-z0-9._]+}} = llvm.call @erf({{%[A-Za-z0-9._]+}}) : (f64) -> f64
+
+func.func @_QPtest_real4(%arg0: !fir.ref<f32> {fir.bindc_name = "x"}) -> f32 {
+  %0 = fir.alloca f32 {bindc_name = "test_real4", uniq_name = "_QFtest_real4Etest_real4"}
+  %1 = fir.load %arg0 : !fir.ref<f32>
+  %2 = math.erf %1 : f32
+  fir.store %2 to %0 : !fir.ref<f32>
+  %3 = fir.load %0 : !fir.ref<f32>
+  return %3 : f32
+}
+func.func @_QPtest_real8(%arg0: !fir.ref<f64> {fir.bindc_name = "x"}) -> f64 {
+  %0 = fir.alloca f64 {bindc_name = "test_real8", uniq_name = "_QFtest_real8Etest_real8"}
+  %1 = fir.load %arg0 : !fir.ref<f64>
+  %2 = math.erf %1 : f64
+  fir.store %2 to %0 : !fir.ref<f64>
+  %3 = fir.load %0 : !fir.ref<f64>
+  return %3 : f64
+}
+
+//--- erf_precise.fir
+// RUN: fir-opt %t/erf_precise.fir --fir-to-llvm-ir="target=x86_64-unknown-linux-gnu" | FileCheck %t/erf_precise.fir
+// CHECK: @_QPtest_real4
+// CHECK: {{%[A-Za-z0-9._]+}} = llvm.call @erff({{%[A-Za-z0-9._]+}}) : (f32) -> f32
+
+// CHECK: @_QPtest_real8
+// CHECK: {{%[A-Za-z0-9._]+}} = llvm.call @erf({{%[A-Za-z0-9._]+}}) : (f64) -> f64
+
+func.func @_QPtest_real4(%arg0: !fir.ref<f32> {fir.bindc_name = "x"}) -> f32 {
+  %0 = fir.alloca f32 {bindc_name = "test_real4", uniq_name = "_QFtest_real4Etest_real4"}
+  %1 = fir.load %arg0 : !fir.ref<f32>
+  %2 = fir.call @erff(%1) : (f32) -> f32
+  fir.store %2 to %0 : !fir.ref<f32>
+  %3 = fir.load %0 : !fir.ref<f32>
+  return %3 : f32
+}
+func.func @_QPtest_real8(%arg0: !fir.ref<f64> {fir.bindc_name = "x"}) -> f64 {
+  %0 = fir.alloca f64 {bindc_name = "test_real8", uniq_name = "_QFtest_real8Etest_real8"}
+  %1 = fir.load %arg0 : !fir.ref<f64>
+  %2 = fir.call @erf(%1) : (f64) -> f64
+  fir.store %2 to %0 : !fir.ref<f64>
+  %3 = fir.load %0 : !fir.ref<f64>
+  return %3 : f64
+}
+func.func private @erff(f32) -> f32
+func.func private @erf(f64) -> f64
+
+//--- exp_fast.fir
+// RUN: fir-opt %t/exp_fast.fir --fir-to-llvm-ir="target=x86_64-unknown-linux-gnu" | FileCheck %t/exp_fast.fir
+// CHECK: @_QPtest_real4
+// CHECK: {{%[A-Za-z0-9._]+}} = "llvm.intr.exp"({{%[A-Za-z0-9._]+}}) : (f32) -> f32
+
+// CHECK: @_QPtest_real8
+// CHECK: {{%[A-Za-z0-9._]+}} = "llvm.intr.exp"({{%[A-Za-z0-9._]+}}) : (f64) -> f64
+
+func.func @_QPtest_real4(%arg0: !fir.ref<f32> {fir.bindc_name = "x"}) -> f32 {
+  %0 = fir.alloca f32 {bindc_name = "test_real4", uniq_name = "_QFtest_real4Etest_real4"}
+  %1 = fir.load %arg0 : !fir.ref<f32>
+  %2 = math.exp %1 : f32
+  fir.store %2 to %0 : !fir.ref<f32>
+  %3 = fir.load %0 : !fir.ref<f32>
+  return %3 : f32
+}
+func.func @_QPtest_real8(%arg0: !fir.ref<f64> {fir.bindc_name = "x"}) -> f64 {
+  %0 = fir.alloca f64 {bindc_name = "test_real8", uniq_name = "_QFtest_real8Etest_real8"}
+  %1 = fir.load %arg0 : !fir.ref<f64>
+  %2 = math.exp %1 : f64
+  fir.store %2 to %0 : !fir.ref<f64>
+  %3 = fir.load %0 : !fir.ref<f64>
+  return %3 : f64
+}
+
+//--- exp_relaxed.fir
+// RUN: fir-opt %t/exp_relaxed.fir --fir-to-llvm-ir="target=x86_64-unknown-linux-gnu" | FileCheck %t/exp_relaxed.fir
+// CHECK: @_QPtest_real4
+// CHECK: {{%[A-Za-z0-9._]+}} = "llvm.intr.exp"({{%[A-Za-z0-9._]+}}) : (f32) -> f32
+
+// CHECK: @_QPtest_real8
+// CHECK: {{%[A-Za-z0-9._]+}} = "llvm.intr.exp"({{%[A-Za-z0-9._]+}}) : (f64) -> f64
+
+func.func @_QPtest_real4(%arg0: !fir.ref<f32> {fir.bindc_name = "x"}) -> f32 {
+  %0 = fir.alloca f32 {bindc_name = "test_real4", uniq_name = "_QFtest_real4Etest_real4"}
+  %1 = fir.load %arg0 : !fir.ref<f32>
+  %2 = math.exp %1 : f32
+  fir.store %2 to %0 : !fir.ref<f32>
+  %3 = fir.load %0 : !fir.ref<f32>
+  return %3 : f32
+}
+func.func @_QPtest_real8(%arg0: !fir.ref<f64> {fir.bindc_name = "x"}) -> f64 {
+  %0 = fir.alloca f64 {bindc_name = "test_real8", uniq_name = "_QFtest_real8Etest_real8"}
+  %1 = fir.load %arg0 : !fir.ref<f64>
+  %2 = math.exp %1 : f64
+  fir.store %2 to %0 : !fir.ref<f64>
+  %3 = fir.load %0 : !fir.ref<f64>
+  return %3 : f64
+}
+
+//--- exp_precise.fir
+// RUN: fir-opt %t/exp_precise.fir --fir-to-llvm-ir="target=x86_64-unknown-linux-gnu" | FileCheck %t/exp_precise.fir
+// CHECK: @_QPtest_real4
+// CHECK: {{%[A-Za-z0-9._]+}} = llvm.call @expf({{%[A-Za-z0-9._]+}}) : (f32) -> f32
+
+// CHECK: @_QPtest_real8
+// CHECK: {{%[A-Za-z0-9._]+}} = llvm.call @exp({{%[A-Za-z0-9._]+}}) : (f64) -> f64
+
+func.func @_QPtest_real4(%arg0: !fir.ref<f32> {fir.bindc_name = "x"}) -> f32 {
+  %0 = fir.alloca f32 {bindc_name = "test_real4", uniq_name = "_QFtest_real4Etest_real4"}
+  %1 = fir.load %arg0 : !fir.ref<f32>
+  %2 = fir.call @expf(%1) : (f32) -> f32
+  fir.store %2 to %0 : !fir.ref<f32>
+  %3 = fir.load %0 : !fir.ref<f32>
+  return %3 : f32
+}
+func.func @_QPtest_real8(%arg0: !fir.ref<f64> {fir.bindc_name = "x"}) -> f64 {
+  %0 = fir.alloca f64 {bindc_name = "test_real8", uniq_name = "_QFtest_real8Etest_real8"}
+  %1 = fir.load %arg0 : !fir.ref<f64>
+  %2 = fir.call @exp(%1) : (f64) -> f64
+  fir.store %2 to %0 : !fir.ref<f64>
+  %3 = fir.load %0 : !fir.ref<f64>
+  return %3 : f64
+}
+func.func private @expf(f32) -> f32
+func.func private @exp(f64) -> f64
+
+//--- floor_fast.fir
+// RUN: fir-opt %t/floor_fast.fir --fir-to-llvm-ir="target=x86_64-unknown-linux-gnu" | FileCheck %t/floor_fast.fir
+// CHECK: @_QPtest_real4
+// CHECK: {{%[A-Za-z0-9._]+}} = "llvm.intr.floor"({{%[A-Za-z0-9._]+}}) : (f32) -> f32
+
+// CHECK: @_QPtest_real8
+// CHECK: {{%[A-Za-z0-9._]+}} = "llvm.intr.floor"({{%[A-Za-z0-9._]+}}) : (f64) -> f64
+
+func.func @_QPtest_real4(%arg0: !fir.ref<f32> {fir.bindc_name = "x"}) -> f32 {
+  %0 = fir.alloca f32 {bindc_name = "test_real4", uniq_name = "_QFtest_real4Etest_real4"}
+  %1 = fir.load %arg0 : !fir.ref<f32>
+  %2 = math.floor %1 : f32
+  %3 = fir.convert %2 : (f32) -> i32
+  %4 = fir.convert %3 : (i32) -> f32
+  fir.store %4 to %0 : !fir.ref<f32>
+  %5 = fir.load %0 : !fir.ref<f32>
+  return %5 : f32
+}
+func.func @_QPtest_real8(%arg0: !fir.ref<f64> {fir.bindc_name = "x"}) -> f64 {
+  %0 = fir.alloca f64 {bindc_name = "test_real8", uniq_name = "_QFtest_real8Etest_real8"}
+  %1 = fir.load %arg0 : !fir.ref<f64>
+  %2 = math.floor %1 : f64
+  %3 = fir.convert %2 : (f64) -> i32
+  %4 = fir.convert %3 : (i32) -> f64
+  fir.store %4 to %0 : !fir.ref<f64>
+  %5 = fir.load %0 : !fir.ref<f64>
+  return %5 : f64
+}
+
+//--- floor_relaxed.fir
+// RUN: fir-opt %t/floor_relaxed.fir --fir-to-llvm-ir="target=x86_64-unknown-linux-gnu" | FileCheck %t/floor_relaxed.fir
+// CHECK: @_QPtest_real4
+// CHECK: {{%[A-Za-z0-9._]+}} = "llvm.intr.floor"({{%[A-Za-z0-9._]+}}) : (f32) -> f32
+
+// CHECK: @_QPtest_real8
+// CHECK: {{%[A-Za-z0-9._]+}} = "llvm.intr.floor"({{%[A-Za-z0-9._]+}}) : (f64) -> f64
+
+func.func @_QPtest_real4(%arg0: !fir.ref<f32> {fir.bindc_name = "x"}) -> f32 {
+  %0 = fir.alloca f32 {bindc_name = "test_real4", uniq_name = "_QFtest_real4Etest_real4"}
+  %1 = fir.load %arg0 : !fir.ref<f32>
+  %2 = math.floor %1 : f32
+  %3 = fir.convert %2 : (f32) -> i32
+  %4 = fir.convert %3 : (i32) -> f32
+  fir.store %4 to %0 : !fir.ref<f32>
+  %5 = fir.load %0 : !fir.ref<f32>
+  return %5 : f32
+}
+func.func @_QPtest_real8(%arg0: !fir.ref<f64> {fir.bindc_name = "x"}) -> f64 {
+  %0 = fir.alloca f64 {bindc_name = "test_real8", uniq_name = "_QFtest_real8Etest_real8"}
+  %1 = fir.load %arg0 : !fir.ref<f64>
+  %2 = math.floor %1 : f64
+  %3 = fir.convert %2 : (f64) -> i32
+  %4 = fir.convert %3 : (i32) -> f64
+  fir.store %4 to %0 : !fir.ref<f64>
+  %5 = fir.load %0 : !fir.ref<f64>
+  return %5 : f64
+}
+
+//--- floor_precise.fir
+// RUN: fir-opt %t/floor_precise.fir --fir-to-llvm-ir="target=x86_64-unknown-linux-gnu" | FileCheck %t/floor_precise.fir
+// CHECK: @_QPtest_real4
+// CHECK: {{%[A-Za-z0-9._]+}} = llvm.call @floorf({{%[A-Za-z0-9._]+}}) : (f32) -> f32
+
+// CHECK: @_QPtest_real8
+// CHECK: {{%[A-Za-z0-9._]+}} = llvm.call @floor({{%[A-Za-z0-9._]+}}) : (f64) -> f64
+
+func.func @_QPtest_real4(%arg0: !fir.ref<f32> {fir.bindc_name = "x"}) -> f32 {
+  %0 = fir.alloca f32 {bindc_name = "test_real4", uniq_name = "_QFtest_real4Etest_real4"}
+  %1 = fir.load %arg0 : !fir.ref<f32>
+  %2 = fir.call @floorf(%1) : (f32) -> f32
+  %3 = fir.convert %2 : (f32) -> i32
+  %4 = fir.convert %3 : (i32) -> f32
+  fir.store %4 to %0 : !fir.ref<f32>
+  %5 = fir.load %0 : !fir.ref<f32>
+  return %5 : f32
+}
+func.func @_QPtest_real8(%arg0: !fir.ref<f64> {fir.bindc_name = "x"}) -> f64 {
+  %0 = fir.alloca f64 {bindc_name = "test_real8", uniq_name = "_QFtest_real8Etest_real8"}
+  %1 = fir.load %arg0 : !fir.ref<f64>
+  %2 = fir.call @floor(%1) : (f64) -> f64
+  %3 = fir.convert %2 : (f64) -> i32
+  %4 = fir.convert %3 : (i32) -> f64
+  fir.store %4 to %0 : !fir.ref<f64>
+  %5 = fir.load %0 : !fir.ref<f64>
+  return %5 : f64
+}
+func.func private @floorf(f32) -> f32
+func.func private @floor(f64) -> f64
+
+//--- log_fast.fir
+// RUN: fir-opt %t/log_fast.fir --fir-to-llvm-ir="target=x86_64-unknown-linux-gnu" | FileCheck %t/log_fast.fir
+// CHECK: @_QPtest_real4
+// CHECK: {{%[A-Za-z0-9._]+}} = "llvm.intr.log"({{%[A-Za-z0-9._]+}}) : (f32) -> f32
+
+// CHECK: @_QPtest_real8
+// CHECK: {{%[A-Za-z0-9._]+}} = "llvm.intr.log"({{%[A-Za-z0-9._]+}}) : (f64) -> f64
+
+func.func @_QPtest_real4(%arg0: !fir.ref<f32> {fir.bindc_name = "x"}) -> f32 {
+  %0 = fir.alloca f32 {bindc_name = "test_real4", uniq_name = "_QFtest_real4Etest_real4"}
+  %1 = fir.load %arg0 : !fir.ref<f32>
+  %2 = math.log %1 : f32
+  fir.store %2 to %0 : !fir.ref<f32>
+  %3 = fir.load %0 : !fir.ref<f32>
+  return %3 : f32
+}
+func.func @_QPtest_real8(%arg0: !fir.ref<f64> {fir.bindc_name = "x"}) -> f64 {
+  %0 = fir.alloca f64 {bindc_name = "test_real8", uniq_name = "_QFtest_real8Etest_real8"}
+  %1 = fir.load %arg0 : !fir.ref<f64>
+  %2 = math.log %1 : f64
+  fir.store %2 to %0 : !fir.ref<f64>
+  %3 = fir.load %0 : !fir.ref<f64>
+  return %3 : f64
+}
+
+//--- log_relaxed.fir
+// RUN: fir-opt %t/log_relaxed.fir --fir-to-llvm-ir="target=x86_64-unknown-linux-gnu" | FileCheck %t/log_relaxed.fir
+// CHECK: @_QPtest_real4
+// CHECK: {{%[A-Za-z0-9._]+}} = "llvm.intr.log"({{%[A-Za-z0-9._]+}}) : (f32) -> f32
+
+// CHECK: @_QPtest_real8
+// CHECK: {{%[A-Za-z0-9._]+}} = "llvm.intr.log"({{%[A-Za-z0-9._]+}}) : (f64) -> f64
+
+func.func @_QPtest_real4(%arg0: !fir.ref<f32> {fir.bindc_name = "x"}) -> f32 {
+  %0 = fir.alloca f32 {bindc_name = "test_real4", uniq_name = "_QFtest_real4Etest_real4"}
+  %1 = fir.load %arg0 : !fir.ref<f32>
+  %2 = math.log %1 : f32
+  fir.store %2 to %0 : !fir.ref<f32>
+  %3 = fir.load %0 : !fir.ref<f32>
+  return %3 : f32
+}
+func.func @_QPtest_real8(%arg0: !fir.ref<f64> {fir.bindc_name = "x"}) -> f64 {
+  %0 = fir.alloca f64 {bindc_name = "test_real8", uniq_name = "_QFtest_real8Etest_real8"}
+  %1 = fir.load %arg0 : !fir.ref<f64>
+  %2 = math.log %1 : f64
+  fir.store %2 to %0 : !fir.ref<f64>
+  %3 = fir.load %0 : !fir.ref<f64>
+  return %3 : f64
+}
+
+//--- log_precise.fir
+// RUN: fir-opt %t/log_precise.fir --fir-to-llvm-ir="target=x86_64-unknown-linux-gnu" | FileCheck %t/log_precise.fir
+// CHECK: @_QPtest_real4
+// CHECK: {{%[A-Za-z0-9._]+}} = llvm.call @logf({{%[A-Za-z0-9._]+}}) : (f32) -> f32
+
+// CHECK: @_QPtest_real8
+// CHECK: {{%[A-Za-z0-9._]+}} = llvm.call @log({{%[A-Za-z0-9._]+}}) : (f64) -> f64
+
+func.func @_QPtest_real4(%arg0: !fir.ref<f32> {fir.bindc_name = "x"}) -> f32 {
+  %0 = fir.alloca f32 {bindc_name = "test_real4", uniq_name = "_QFtest_real4Etest_real4"}
+  %1 = fir.load %arg0 : !fir.ref<f32>
+  %2 = fir.call @logf(%1) : (f32) -> f32
+  fir.store %2 to %0 : !fir.ref<f32>
+  %3 = fir.load %0 : !fir.ref<f32>
+  return %3 : f32
+}
+func.func @_QPtest_real8(%arg0: !fir.ref<f64> {fir.bindc_name = "x"}) -> f64 {
+  %0 = fir.alloca f64 {bindc_name = "test_real8", uniq_name = "_QFtest_real8Etest_real8"}
+  %1 = fir.load %arg0 : !fir.ref<f64>
+  %2 = fir.call @log(%1) : (f64) -> f64
+  fir.store %2 to %0 : !fir.ref<f64>
+  %3 = fir.load %0 : !fir.ref<f64>
+  return %3 : f64
+}
+func.func private @logf(f32) -> f32
+func.func private @log(f64) -> f64
+
+//--- log10_fast.fir
+// RUN: fir-opt %t/log10_fast.fir --fir-to-llvm-ir="target=x86_64-unknown-linux-gnu" | FileCheck %t/log10_fast.fir
+// CHECK: @_QPtest_real4
+// CHECK: {{%[A-Za-z0-9._]+}} = "llvm.intr.log10"({{%[A-Za-z0-9._]+}}) : (f32) -> f32
+
+// CHECK: @_QPtest_real8
+// CHECK: {{%[A-Za-z0-9._]+}} = "llvm.intr.log10"({{%[A-Za-z0-9._]+}}) : (f64) -> f64
+
+func.func @_QPtest_real4(%arg0: !fir.ref<f32> {fir.bindc_name = "x"}) -> f32 {
+  %0 = fir.alloca f32 {bindc_name = "test_real4", uniq_name = "_QFtest_real4Etest_real4"}
+  %1 = fir.load %arg0 : !fir.ref<f32>
+  %2 = math.log10 %1 : f32
+  fir.store %2 to %0 : !fir.ref<f32>
+  %3 = fir.load %0 : !fir.ref<f32>
+  return %3 : f32
+}
+func.func @_QPtest_real8(%arg0: !fir.ref<f64> {fir.bindc_name = "x"}) -> f64 {
+  %0 = fir.alloca f64 {bindc_name = "test_real8", uniq_name = "_QFtest_real8Etest_real8"}
+  %1 = fir.load %arg0 : !fir.ref<f64>
+  %2 = math.log10 %1 : f64
+  fir.store %2 to %0 : !fir.ref<f64>
+  %3 = fir.load %0 : !fir.ref<f64>
+  return %3 : f64
+}
+
+//--- log10_relaxed.fir
+// RUN: fir-opt %t/log10_relaxed.fir --fir-to-llvm-ir="target=x86_64-unknown-linux-gnu" | FileCheck %t/log10_relaxed.fir
+// CHECK: @_QPtest_real4
+// CHECK: {{%[A-Za-z0-9._]+}} = "llvm.intr.log10"({{%[A-Za-z0-9._]+}}) : (f32) -> f32
+
+// CHECK: @_QPtest_real8
+// CHECK: {{%[A-Za-z0-9._]+}} = "llvm.intr.log10"({{%[A-Za-z0-9._]+}}) : (f64) -> f64
+
+func.func @_QPtest_real4(%arg0: !fir.ref<f32> {fir.bindc_name = "x"}) -> f32 {
+  %0 = fir.alloca f32 {bindc_name = "test_real4", uniq_name = "_QFtest_real4Etest_real4"}
+  %1 = fir.load %arg0 : !fir.ref<f32>
+  %2 = math.log10 %1 : f32
+  fir.store %2 to %0 : !fir.ref<f32>
+  %3 = fir.load %0 : !fir.ref<f32>
+  return %3 : f32
+}
+func.func @_QPtest_real8(%arg0: !fir.ref<f64> {fir.bindc_name = "x"}) -> f64 {
+  %0 = fir.alloca f64 {bindc_name = "test_real8", uniq_name = "_QFtest_real8Etest_real8"}
+  %1 = fir.load %arg0 : !fir.ref<f64>
+  %2 = math.log10 %1 : f64
+  fir.store %2 to %0 : !fir.ref<f64>
+  %3 = fir.load %0 : !fir.ref<f64>
+  return %3 : f64
+}
+
+//--- log10_precise.fir
+// RUN: fir-opt %t/log10_precise.fir --fir-to-llvm-ir="target=x86_64-unknown-linux-gnu" | FileCheck %t/log10_precise.fir
+// CHECK: @_QPtest_real4
+// CHECK: {{%[A-Za-z0-9._]+}} = llvm.call @log10f({{%[A-Za-z0-9._]+}}) : (f32) -> f32
+
+// CHECK: @_QPtest_real8
+// CHECK: {{%[A-Za-z0-9._]+}} = llvm.call @log10({{%[A-Za-z0-9._]+}}) : (f64) -> f64
+
+func.func @_QPtest_real4(%arg0: !fir.ref<f32> {fir.bindc_name = "x"}) -> f32 {
+  %0 = fir.alloca f32 {bindc_name = "test_real4", uniq_name = "_QFtest_real4Etest_real4"}
+  %1 = fir.load %arg0 : !fir.ref<f32>
+  %2 = fir.call @log10f(%1) : (f32) -> f32
+  fir.store %2 to %0 : !fir.ref<f32>
+  %3 = fir.load %0 : !fir.ref<f32>
+  return %3 : f32
+}
+func.func @_QPtest_real8(%arg0: !fir.ref<f64> {fir.bindc_name = "x"}) -> f64 {
+  %0 = fir.alloca f64 {bindc_name = "test_real8", uniq_name = "_QFtest_real8Etest_real8"}
+  %1 = fir.load %arg0 : !fir.ref<f64>
+  %2 = fir.call @log10(%1) : (f64) -> f64
+  fir.store %2 to %0 : !fir.ref<f64>
+  %3 = fir.load %0 : !fir.ref<f64>
+  return %3 : f64
+}
+func.func private @log10f(f32) -> f32
+func.func private @log10(f64) -> f64
+
+//--- nint_fast.fir
+// RUN: fir-opt %t/nint_fast.fir --fir-to-llvm-ir="target=x86_64-unknown-linux-gnu" | FileCheck %t/nint_fast.fir
+// CHECK: @_QPtest_real4
+// CHECK: {{%[A-Za-z0-9._]+}} = llvm.call @llvm.lround.i32.f32({{%[A-Za-z0-9._]+}}) : (f32) -> i32
+// CHECK: {{%[A-Za-z0-9._]+}} = llvm.call @llvm.lround.i64.f32({{%[A-Za-z0-9._]+}}) : (f32) -> i64
+
+// CHECK: @_QPtest_real8
+// CHECK: {{%[A-Za-z0-9._]+}} = llvm.call @llvm.lround.i32.f64({{%[A-Za-z0-9._]+}}) : (f64) -> i32
+// CHECK: {{%[A-Za-z0-9._]+}} = llvm.call @llvm.lround.i64.f64({{%[A-Za-z0-9._]+}}) : (f64) -> i64
+
+func.func @_QPtest_real4(%arg0: !fir.ref<f32> {fir.bindc_name = "x"}) -> f32 {
+  %0 = fir.alloca f32 {bindc_name = "test_real4", uniq_name = "_QFtest_real4Etest_real4"}
+  %1 = fir.load %arg0 : !fir.ref<f32>
+  %2 = fir.call @llvm.lround.i32.f32(%1) : (f32) -> i32
+  %3 = fir.convert %2 : (i32) -> i64
+  %4 = fir.load %arg0 : !fir.ref<f32>
+  %5 = fir.call @llvm.lround.i64.f32(%4) : (f32) -> i64
+  %6 = arith.addi %3, %5 : i64
+  %7 = fir.convert %6 : (i64) -> f32
+  fir.store %7 to %0 : !fir.ref<f32>
+  %8 = fir.load %0 : !fir.ref<f32>
+  return %8 : f32
+}
+func.func @_QPtest_real8(%arg0: !fir.ref<f64> {fir.bindc_name = "x"}) -> f64 {
+  %0 = fir.alloca f64 {bindc_name = "test_real8", uniq_name = "_QFtest_real8Etest_real8"}
+  %1 = fir.load %arg0 : !fir.ref<f64>
+  %2 = fir.call @llvm.lround.i32.f64(%1) : (f64) -> i32
+  %3 = fir.convert %2 : (i32) -> i64
+  %4 = fir.load %arg0 : !fir.ref<f64>
+  %5 = fir.call @llvm.lround.i64.f64(%4) : (f64) -> i64
+  %6 = arith.addi %3, %5 : i64
+  %7 = fir.convert %6 : (i64) -> f64
+  fir.store %7 to %0 : !fir.ref<f64>
+  %8 = fir.load %0 : !fir.ref<f64>
+  return %8 : f64
+}
+func.func private @llvm.lround.i32.f32(f32) -> i32
+func.func private @llvm.lround.i64.f32(f32) -> i64
+func.func private @llvm.lround.i32.f64(f64) -> i32
+func.func private @llvm.lround.i64.f64(f64) -> i64
+
+//--- nint_relaxed.fir
+// RUN: fir-opt %t/nint_relaxed.fir --fir-to-llvm-ir="target=x86_64-unknown-linux-gnu" | FileCheck %t/nint_relaxed.fir
+// CHECK: @_QPtest_real4
+// CHECK: {{%[A-Za-z0-9._]+}} = llvm.call @llvm.lround.i32.f32({{%[A-Za-z0-9._]+}}) : (f32) -> i32
+// CHECK: {{%[A-Za-z0-9._]+}} = llvm.call @llvm.lround.i64.f32({{%[A-Za-z0-9._]+}}) : (f32) -> i64
+
+// CHECK: @_QPtest_real8
+// CHECK: {{%[A-Za-z0-9._]+}} = llvm.call @llvm.lround.i32.f64({{%[A-Za-z0-9._]+}}) : (f64) -> i32
+// CHECK: {{%[A-Za-z0-9._]+}} = llvm.call @llvm.lround.i64.f64({{%[A-Za-z0-9._]+}}) : (f64) -> i64
+
+func.func @_QPtest_real4(%arg0: !fir.ref<f32> {fir.bindc_name = "x"}) -> f32 {
+  %0 = fir.alloca f32 {bindc_name = "test_real4", uniq_name = "_QFtest_real4Etest_real4"}
+  %1 = fir.load %arg0 : !fir.ref<f32>
+  %2 = fir.call @llvm.lround.i32.f32(%1) : (f32) -> i32
+  %3 = fir.convert %2 : (i32) -> i64
+  %4 = fir.load %arg0 : !fir.ref<f32>
+  %5 = fir.call @llvm.lround.i64.f32(%4) : (f32) -> i64
+  %6 = arith.addi %3, %5 : i64
+  %7 = fir.convert %6 : (i64) -> f32
+  fir.store %7 to %0 : !fir.ref<f32>
+  %8 = fir.load %0 : !fir.ref<f32>
+  return %8 : f32
+}
+func.func @_QPtest_real8(%arg0: !fir.ref<f64> {fir.bindc_name = "x"}) -> f64 {
+  %0 = fir.alloca f64 {bindc_name = "test_real8", uniq_name = "_QFtest_real8Etest_real8"}
+  %1 = fir.load %arg0 : !fir.ref<f64>
+  %2 = fir.call @llvm.lround.i32.f64(%1) : (f64) -> i32
+  %3 = fir.convert %2 : (i32) -> i64
+  %4 = fir.load %arg0 : !fir.ref<f64>
+  %5 = fir.call @llvm.lround.i64.f64(%4) : (f64) -> i64
+  %6 = arith.addi %3, %5 : i64
+  %7 = fir.convert %6 : (i64) -> f64
+  fir.store %7 to %0 : !fir.ref<f64>
+  %8 = fir.load %0 : !fir.ref<f64>
+  return %8 : f64
+}
+func.func private @llvm.lround.i32.f32(f32) -> i32
+func.func private @llvm.lround.i64.f32(f32) -> i64
+func.func private @llvm.lround.i32.f64(f64) -> i32
+func.func private @llvm.lround.i64.f64(f64) -> i64
+
+//--- nint_precise.fir
+// RUN: fir-opt %t/nint_precise.fir --fir-to-llvm-ir="target=x86_64-unknown-linux-gnu" | FileCheck %t/nint_precise.fir
+// CHECK: @_QPtest_real4
+// CHECK: {{%[A-Za-z0-9._]+}} = llvm.call @llvm.lround.i32.f32({{%[A-Za-z0-9._]+}}) : (f32) -> i32
+// CHECK: {{%[A-Za-z0-9._]+}} = llvm.call @llvm.lround.i64.f32({{%[A-Za-z0-9._]+}}) : (f32) -> i64
+
+// CHECK: @_QPtest_real8
+// CHECK: {{%[A-Za-z0-9._]+}} = llvm.call @llvm.lround.i32.f64({{%[A-Za-z0-9._]+}}) : (f64) -> i32
+// CHECK: {{%[A-Za-z0-9._]+}} = llvm.call @llvm.lround.i64.f64({{%[A-Za-z0-9._]+}}) : (f64) -> i64
+
+func.func @_QPtest_real4(%arg0: !fir.ref<f32> {fir.bindc_name = "x"}) -> f32 {
+  %0 = fir.alloca f32 {bindc_name = "test_real4", uniq_name = "_QFtest_real4Etest_real4"}
+  %1 = fir.load %arg0 : !fir.ref<f32>
+  %2 = fir.call @llvm.lround.i32.f32(%1) : (f32) -> i32
+  %3 = fir.convert %2 : (i32) -> i64
+  %4 = fir.load %arg0 : !fir.ref<f32>
+  %5 = fir.call @llvm.lround.i64.f32(%4) : (f32) -> i64
+  %6 = arith.addi %3, %5 : i64
+  %7 = fir.convert %6 : (i64) -> f32
+  fir.store %7 to %0 : !fir.ref<f32>
+  %8 = fir.load %0 : !fir.ref<f32>
+  return %8 : f32
+}
+func.func @_QPtest_real8(%arg0: !fir.ref<f64> {fir.bindc_name = "x"}) -> f64 {
+  %0 = fir.alloca f64 {bindc_name = "test_real8", uniq_name = "_QFtest_real8Etest_real8"}
+  %1 = fir.load %arg0 : !fir.ref<f64>
+  %2 = fir.call @llvm.lround.i32.f64(%1) : (f64) -> i32
+  %3 = fir.convert %2 : (i32) -> i64
+  %4 = fir.load %arg0 : !fir.ref<f64>
+  %5 = fir.call @llvm.lround.i64.f64(%4) : (f64) -> i64
+  %6 = arith.addi %3, %5 : i64
+  %7 = fir.convert %6 : (i64) -> f64
+  fir.store %7 to %0 : !fir.ref<f64>
+  %8 = fir.load %0 : !fir.ref<f64>
+  return %8 : f64
+}
+func.func private @llvm.lround.i32.f32(f32) -> i32
+func.func private @llvm.lround.i64.f32(f32) -> i64
+func.func private @llvm.lround.i32.f64(f64) -> i32
+func.func private @llvm.lround.i64.f64(f64) -> i64
+
+//--- exponentiation_fast.fir
+// RUN: fir-opt %t/exponentiation_fast.fir --fir-to-llvm-ir="target=x86_64-unknown-linux-gnu" | FileCheck %t/exponentiation_fast.fir
+// CHECK: @_QPtest_real4
+// CHECK: [[STOI:%[A-Za-z0-9._]+]] = llvm.sext {{%[A-Za-z0-9._]+}} : i16 to i32
+// CHECK: {{%[A-Za-z0-9._]+}} = llvm.call @llvm.powi.f32.i32({{%[A-Za-z0-9._]+}}, [[STOI]]) : (f32, i32) -> f32
+// CHECK: {{%[A-Za-z0-9._]+}} = "llvm.intr.pow"({{%[A-Za-z0-9._]+}}, {{%[A-Za-z0-9._]+}}) : (f32, f32) -> f32
+// CHECK: {{%[A-Za-z0-9._]+}} = llvm.call @llvm.powi.f32.i32({{%[A-Za-z0-9._]+}}, {{%[A-Za-z0-9._]+}}) : (f32, i32) -> f32
+
+// CHECK: @_QPtest_real8
+// CHECK: [[STOI:%[A-Za-z0-9._]+]] = llvm.sext {{%[A-Za-z0-9._]+}} : i16 to i32
+// CHECK: {{%[A-Za-z0-9._]+}} = llvm.call @llvm.powi.f64.i32({{%[A-Za-z0-9._]+}}, [[STOI]]) : (f64, i32) -> f64
+// CHECK: {{%[A-Za-z0-9._]+}} = "llvm.intr.pow"({{%[A-Za-z0-9._]+}}, {{%[A-Za-z0-9._]+}}) : (f64, f64) -> f64
+// CHECK: {{%[A-Za-z0-9._]+}} = llvm.call @llvm.powi.f64.i32({{%[A-Za-z0-9._]+}}, {{%[A-Za-z0-9._]+}}) : (f64, i32) -> f64
+
+func.func @_QPtest_real4(%arg0: !fir.ref<f32> {fir.bindc_name = "x"}, %arg1: !fir.ref<f32> {fir.bindc_name = "y"}, %arg2: !fir.ref<i16> {fir.bindc_name = "s"}, %arg3: !fir.ref<i32> {fir.bindc_name = "i"}) -> f32 {
+  %0 = fir.alloca f32 {bindc_name = "test_real4", uniq_name = "_QFtest_real4Etest_real4"}
+  %1 = fir.load %arg0 : !fir.ref<f32>
+  %2 = fir.load %arg2 : !fir.ref<i16>
+  %3 = fir.convert %2 : (i16) -> i32
+  %4 = fir.call @llvm.powi.f32.i32(%1, %3) : (f32, i32) -> f32
+  %5 = fir.load %arg0 : !fir.ref<f32>
+  %6 = fir.load %arg1 : !fir.ref<f32>
+  %7 = math.powf %5, %6 : f32
+  %8 = arith.addf %4, %7 : f32
+  %9 = fir.load %arg0 : !fir.ref<f32>
+  %10 = fir.load %arg3 : !fir.ref<i32>
+  %11 = fir.call @llvm.powi.f32.i32(%9, %10) : (f32, i32) -> f32
+  %12 = arith.addf %8, %11 : f32
+  fir.store %12 to %0 : !fir.ref<f32>
+  %13 = fir.load %0 : !fir.ref<f32>
+  return %13 : f32
+}
+func.func @_QPtest_real8(%arg0: !fir.ref<f64> {fir.bindc_name = "x"}, %arg1: !fir.ref<f64> {fir.bindc_name = "y"}, %arg2: !fir.ref<i16> {fir.bindc_name = "s"}, %arg3: !fir.ref<i32> {fir.bindc_name = "i"}) -> f64 {
+  %0 = fir.alloca f64 {bindc_name = "test_real8", uniq_name = "_QFtest_real8Etest_real8"}
+  %1 = fir.load %arg0 : !fir.ref<f64>
+  %2 = fir.load %arg2 : !fir.ref<i16>
+  %3 = fir.convert %2 : (i16) -> i32
+  %4 = fir.call @llvm.powi.f64.i32(%1, %3) : (f64, i32) -> f64
+  %5 = fir.load %arg0 : !fir.ref<f64>
+  %6 = fir.load %arg1 : !fir.ref<f64>
+  %7 = math.powf %5, %6 : f64
+  %8 = arith.addf %4, %7 : f64
+  %9 = fir.load %arg0 : !fir.ref<f64>
+  %10 = fir.load %arg3 : !fir.ref<i32>
+  %11 = fir.call @llvm.powi.f64.i32(%9, %10) : (f64, i32) -> f64
+  %12 = arith.addf %8, %11 : f64
+  fir.store %12 to %0 : !fir.ref<f64>
+  %13 = fir.load %0 : !fir.ref<f64>
+  return %13 : f64
+}
+func.func private @llvm.powi.f32.i32(f32, i32) -> f32
+func.func private @llvm.powi.f64.i32(f64, i32) -> f64
+
+//--- exponentiation_relaxed.fir
+// RUN: fir-opt %t/exponentiation_relaxed.fir --fir-to-llvm-ir="target=x86_64-unknown-linux-gnu" | FileCheck %t/exponentiation_relaxed.fir
+// CHECK: @_QPtest_real4
+// CHECK: [[STOI:%[A-Za-z0-9._]+]] = llvm.sext {{%[A-Za-z0-9._]+}} : i16 to i32
+// CHECK: {{%[A-Za-z0-9._]+}} = llvm.call @llvm.powi.f32.i32({{%[A-Za-z0-9._]+}}, [[STOI]]) : (f32, i32) -> f32
+// CHECK: {{%[A-Za-z0-9._]+}} = "llvm.intr.pow"({{%[A-Za-z0-9._]+}}, {{%[A-Za-z0-9._]+}}) : (f32, f32) -> f32
+// CHECK: {{%[A-Za-z0-9._]+}} = llvm.call @llvm.powi.f32.i32({{%[A-Za-z0-9._]+}}, {{%[A-Za-z0-9._]+}}) : (f32, i32) -> f32
+
+// CHECK: @_QPtest_real8
+// CHECK: [[STOI:%[A-Za-z0-9._]+]] = llvm.sext {{%[A-Za-z0-9._]+}} : i16 to i32
+// CHECK: {{%[A-Za-z0-9._]+}} = llvm.call @llvm.powi.f64.i32({{%[A-Za-z0-9._]+}}, [[STOI]]) : (f64, i32) -> f64
+// CHECK: {{%[A-Za-z0-9._]+}} = "llvm.intr.pow"({{%[A-Za-z0-9._]+}}, {{%[A-Za-z0-9._]+}}) : (f64, f64) -> f64
+// CHECK: {{%[A-Za-z0-9._]+}} = llvm.call @llvm.powi.f64.i32({{%[A-Za-z0-9._]+}}, {{%[A-Za-z0-9._]+}}) : (f64, i32) -> f64
+
+func.func @_QPtest_real4(%arg0: !fir.ref<f32> {fir.bindc_name = "x"}, %arg1: !fir.ref<f32> {fir.bindc_name = "y"}, %arg2: !fir.ref<i16> {fir.bindc_name = "s"}, %arg3: !fir.ref<i32> {fir.bindc_name = "i"}) -> f32 {
+  %0 = fir.alloca f32 {bindc_name = "test_real4", uniq_name = "_QFtest_real4Etest_real4"}
+  %1 = fir.load %arg0 : !fir.ref<f32>
+  %2 = fir.load %arg2 : !fir.ref<i16>
+  %3 = fir.convert %2 : (i16) -> i32
+  %4 = fir.call @llvm.powi.f32.i32(%1, %3) : (f32, i32) -> f32
+  %5 = fir.load %arg0 : !fir.ref<f32>
+  %6 = fir.load %arg1 : !fir.ref<f32>
+  %7 = math.powf %5, %6 : f32
+  %8 = arith.addf %4, %7 : f32
+  %9 = fir.load %arg0 : !fir.ref<f32>
+  %10 = fir.load %arg3 : !fir.ref<i32>
+  %11 = fir.call @llvm.powi.f32.i32(%9, %10) : (f32, i32) -> f32
+  %12 = arith.addf %8, %11 : f32
+  fir.store %12 to %0 : !fir.ref<f32>
+  %13 = fir.load %0 : !fir.ref<f32>
+  return %13 : f32
+}
+func.func @_QPtest_real8(%arg0: !fir.ref<f64> {fir.bindc_name = "x"}, %arg1: !fir.ref<f64> {fir.bindc_name = "y"}, %arg2: !fir.ref<i16> {fir.bindc_name = "s"}, %arg3: !fir.ref<i32> {fir.bindc_name = "i"}) -> f64 {
+  %0 = fir.alloca f64 {bindc_name = "test_real8", uniq_name = "_QFtest_real8Etest_real8"}
+  %1 = fir.load %arg0 : !fir.ref<f64>
+  %2 = fir.load %arg2 : !fir.ref<i16>
+  %3 = fir.convert %2 : (i16) -> i32
+  %4 = fir.call @llvm.powi.f64.i32(%1, %3) : (f64, i32) -> f64
+  %5 = fir.load %arg0 : !fir.ref<f64>
+  %6 = fir.load %arg1 : !fir.ref<f64>
+  %7 = math.powf %5, %6 : f64
+  %8 = arith.addf %4, %7 : f64
+  %9 = fir.load %arg0 : !fir.ref<f64>
+  %10 = fir.load %arg3 : !fir.ref<i32>
+  %11 = fir.call @llvm.powi.f64.i32(%9, %10) : (f64, i32) -> f64
+  %12 = arith.addf %8, %11 : f64
+  fir.store %12 to %0 : !fir.ref<f64>
+  %13 = fir.load %0 : !fir.ref<f64>
+  return %13 : f64
+}
+func.func private @llvm.powi.f32.i32(f32, i32) -> f32
+func.func private @llvm.powi.f64.i32(f64, i32) -> f64
+
+//--- exponentiation_precise.fir
+// RUN: fir-opt %t/exponentiation_precise.fir --fir-to-llvm-ir="target=x86_64-unknown-linux-gnu" | FileCheck %t/exponentiation_precise.fir
+// CHECK: @_QPtest_real4
+// CHECK: [[STOI:%[A-Za-z0-9._]+]] = llvm.sext {{%[A-Za-z0-9._]+}} : i16 to i32
+// CHECK: {{%[A-Za-z0-9._]+}} = llvm.call @llvm.powi.f32.i32({{%[A-Za-z0-9._]+}}, [[STOI]]) : (f32, i32) -> f32
+// CHECK: {{%[A-Za-z0-9._]+}} = llvm.call @powf({{%[A-Za-z0-9._]+}}, {{%[A-Za-z0-9._]+}}) : (f32, f32) -> f32
+// CHECK: {{%[A-Za-z0-9._]+}} = llvm.call @llvm.powi.f32.i32({{%[A-Za-z0-9._]+}}, {{%[A-Za-z0-9._]+}}) : (f32, i32) -> f32
+
+// CHECK: @_QPtest_real8
+// CHECK: [[STOI:%[A-Za-z0-9._]+]] = llvm.sext {{%[A-Za-z0-9._]+}} : i16 to i32
+// CHECK: {{%[A-Za-z0-9._]+}} = llvm.call @llvm.powi.f64.i32({{%[A-Za-z0-9._]+}}, [[STOI]]) : (f64, i32) -> f64
+// CHECK: {{%[A-Za-z0-9._]+}} = llvm.call @pow({{%[A-Za-z0-9._]+}}, {{%[A-Za-z0-9._]+}}) : (f64, f64) -> f64
+// CHECK: {{%[A-Za-z0-9._]+}} = llvm.call @llvm.powi.f64.i32({{%[A-Za-z0-9._]+}}, {{%[A-Za-z0-9._]+}}) : (f64, i32) -> f64
+
+func.func @_QPtest_real4(%arg0: !fir.ref<f32> {fir.bindc_name = "x"}, %arg1: !fir.ref<f32> {fir.bindc_name = "y"}, %arg2: !fir.ref<i16> {fir.bindc_name = "s"}, %arg3: !fir.ref<i32> {fir.bindc_name = "i"}) -> f32 {
+  %0 = fir.alloca f32 {bindc_name = "test_real4", uniq_name = "_QFtest_real4Etest_real4"}
+  %1 = fir.load %arg0 : !fir.ref<f32>
+  %2 = fir.load %arg2 : !fir.ref<i16>
+  %3 = fir.convert %2 : (i16) -> i32
+  %4 = fir.call @llvm.powi.f32.i32(%1, %3) : (f32, i32) -> f32
+  %5 = fir.load %arg0 : !fir.ref<f32>
+  %6 = fir.load %arg1 : !fir.ref<f32>
+  %7 = fir.call @powf(%5, %6) : (f32, f32) -> f32
+  %8 = arith.addf %4, %7 : f32
+  %9 = fir.load %arg0 : !fir.ref<f32>
+  %10 = fir.load %arg3 : !fir.ref<i32>
+  %11 = fir.call @llvm.powi.f32.i32(%9, %10) : (f32, i32) -> f32
+  %12 = arith.addf %8, %11 : f32
+  fir.store %12 to %0 : !fir.ref<f32>
+  %13 = fir.load %0 : !fir.ref<f32>
+  return %13 : f32
+}
+func.func @_QPtest_real8(%arg0: !fir.ref<f64> {fir.bindc_name = "x"}, %arg1: !fir.ref<f64> {fir.bindc_name = "y"}, %arg2: !fir.ref<i16> {fir.bindc_name = "s"}, %arg3: !fir.ref<i32> {fir.bindc_name = "i"}) -> f64 {
+  %0 = fir.alloca f64 {bindc_name = "test_real8", uniq_name = "_QFtest_real8Etest_real8"}
+  %1 = fir.load %arg0 : !fir.ref<f64>
+  %2 = fir.load %arg2 : !fir.ref<i16>
+  %3 = fir.convert %2 : (i16) -> i32
+  %4 = fir.call @llvm.powi.f64.i32(%1, %3) : (f64, i32) -> f64
+  %5 = fir.load %arg0 : !fir.ref<f64>
+  %6 = fir.load %arg1 : !fir.ref<f64>
+  %7 = fir.call @pow(%5, %6) : (f64, f64) -> f64
+  %8 = arith.addf %4, %7 : f64
+  %9 = fir.load %arg0 : !fir.ref<f64>
+  %10 = fir.load %arg3 : !fir.ref<i32>
+  %11 = fir.call @llvm.powi.f64.i32(%9, %10) : (f64, i32) -> f64
+  %12 = arith.addf %8, %11 : f64
+  fir.store %12 to %0 : !fir.ref<f64>
+  %13 = fir.load %0 : !fir.ref<f64>
+  return %13 : f64
+}
+func.func private @llvm.powi.f32.i32(f32, i32) -> f32
+func.func private @powf(f32, f32) -> f32
+func.func private @llvm.powi.f64.i32(f64, i32) -> f64
+func.func private @pow(f64, f64) -> f64
+
+//--- sign_fast.fir
+// RUN: fir-opt %t/sign_fast.fir --fir-to-llvm-ir="target=x86_64-unknown-linux-gnu" | FileCheck %t/sign_fast.fir
+// CHECK: @_QPtest_real4
+// CHECK: {{%[A-Za-z0-9._]+}} = "llvm.intr.copysign"({{%[A-Za-z0-9._]+}}, {{%[A-Za-z0-9._]+}}) : (f32, f32) -> f32
+
+// CHECK: @_QPtest_real8
+// CHECK: {{%[A-Za-z0-9._]+}} = "llvm.intr.copysign"({{%[A-Za-z0-9._]+}}, {{%[A-Za-z0-9._]+}}) : (f64, f64) -> f64
+
+func.func @_QPtest_real4(%arg0: !fir.ref<f32> {fir.bindc_name = "x"}, %arg1: !fir.ref<f32> {fir.bindc_name = "y"}) -> f32 {
+  %0 = fir.alloca f32 {bindc_name = "test_real4", uniq_name = "_QFtest_real4Etest_real4"}
+  %1 = fir.load %arg0 : !fir.ref<f32>
+  %2 = fir.load %arg1 : !fir.ref<f32>
+  %3 = math.copysign %1, %2 : f32
+  fir.store %3 to %0 : !fir.ref<f32>
+  %4 = fir.load %0 : !fir.ref<f32>
+  return %4 : f32
+}
+func.func @_QPtest_real8(%arg0: !fir.ref<f64> {fir.bindc_name = "x"}, %arg1: !fir.ref<f64> {fir.bindc_name = "y"}) -> f64 {
+  %0 = fir.alloca f64 {bindc_name = "test_real8", uniq_name = "_QFtest_real8Etest_real8"}
+  %1 = fir.load %arg0 : !fir.ref<f64>
+  %2 = fir.load %arg1 : !fir.ref<f64>
+  %3 = math.copysign %1, %2 : f64
+  fir.store %3 to %0 : !fir.ref<f64>
+  %4 = fir.load %0 : !fir.ref<f64>
+  return %4 : f64
+}
+
+//--- sign_relaxed.fir
+// RUN: fir-opt %t/sign_relaxed.fir --fir-to-llvm-ir="target=x86_64-unknown-linux-gnu" | FileCheck %t/sign_relaxed.fir
+// CHECK: @_QPtest_real4
+// CHECK: {{%[A-Za-z0-9._]+}} = "llvm.intr.copysign"({{%[A-Za-z0-9._]+}}, {{%[A-Za-z0-9._]+}}) : (f32, f32) -> f32
+
+// CHECK: @_QPtest_real8
+// CHECK: {{%[A-Za-z0-9._]+}} = "llvm.intr.copysign"({{%[A-Za-z0-9._]+}}, {{%[A-Za-z0-9._]+}}) : (f64, f64) -> f64
+
+func.func @_QPtest_real4(%arg0: !fir.ref<f32> {fir.bindc_name = "x"}, %arg1: !fir.ref<f32> {fir.bindc_name = "y"}) -> f32 {
+  %0 = fir.alloca f32 {bindc_name = "test_real4", uniq_name = "_QFtest_real4Etest_real4"}
+  %1 = fir.load %arg0 : !fir.ref<f32>
+  %2 = fir.load %arg1 : !fir.ref<f32>
+  %3 = math.copysign %1, %2 : f32
+  fir.store %3 to %0 : !fir.ref<f32>
+  %4 = fir.load %0 : !fir.ref<f32>
+  return %4 : f32
+}
+func.func @_QPtest_real8(%arg0: !fir.ref<f64> {fir.bindc_name = "x"}, %arg1: !fir.ref<f64> {fir.bindc_name = "y"}) -> f64 {
+  %0 = fir.alloca f64 {bindc_name = "test_real8", uniq_name = "_QFtest_real8Etest_real8"}
+  %1 = fir.load %arg0 : !fir.ref<f64>
+  %2 = fir.load %arg1 : !fir.ref<f64>
+  %3 = math.copysign %1, %2 : f64
+  fir.store %3 to %0 : !fir.ref<f64>
+  %4 = fir.load %0 : !fir.ref<f64>
+  return %4 : f64
+}
+
+//--- sign_precise.fir
+// RUN: fir-opt %t/sign_precise.fir --fir-to-llvm-ir="target=x86_64-unknown-linux-gnu" | FileCheck %t/sign_precise.fir
+// CHECK: @_QPtest_real4
+// CHECK: {{%[A-Za-z0-9._]+}} = llvm.call @copysignf({{%[A-Za-z0-9._]+}}, {{%[A-Za-z0-9._]+}}) : (f32, f32) -> f32
+
+// CHECK: @_QPtest_real8
+// CHECK: {{%[A-Za-z0-9._]+}} = llvm.call @copysign({{%[A-Za-z0-9._]+}}, {{%[A-Za-z0-9._]+}}) : (f64, f64) -> f64
+
+func.func @_QPtest_real4(%arg0: !fir.ref<f32> {fir.bindc_name = "x"}, %arg1: !fir.ref<f32> {fir.bindc_name = "y"}) -> f32 {
+  %0 = fir.alloca f32 {bindc_name = "test_real4", uniq_name = "_QFtest_real4Etest_real4"}
+  %1 = fir.load %arg0 : !fir.ref<f32>
+  %2 = fir.load %arg1 : !fir.ref<f32>
+  %3 = fir.call @copysignf(%1, %2) : (f32, f32) -> f32
+  fir.store %3 to %0 : !fir.ref<f32>
+  %4 = fir.load %0 : !fir.ref<f32>
+  return %4 : f32
+}
+func.func @_QPtest_real8(%arg0: !fir.ref<f64> {fir.bindc_name = "x"}, %arg1: !fir.ref<f64> {fir.bindc_name = "y"}) -> f64 {
+  %0 = fir.alloca f64 {bindc_name = "test_real8", uniq_name = "_QFtest_real8Etest_real8"}
+  %1 = fir.load %arg0 : !fir.ref<f64>
+  %2 = fir.load %arg1 : !fir.ref<f64>
+  %3 = fir.call @copysign(%1, %2) : (f64, f64) -> f64
+  fir.store %3 to %0 : !fir.ref<f64>
+  %4 = fir.load %0 : !fir.ref<f64>
+  return %4 : f64
+}
+func.func private @copysignf(f32, f32) -> f32
+func.func private @copysign(f64, f64) -> f64
+
+//--- sin_fast.fir
+// RUN: fir-opt %t/sin_fast.fir --fir-to-llvm-ir="target=x86_64-unknown-linux-gnu" | FileCheck %t/sin_fast.fir
+// CHECK: @_QPtest_real4
+// CHECK: {{%[A-Za-z0-9._]+}} = "llvm.intr.sin"({{%[A-Za-z0-9._]+}}) : (f32) -> f32
+
+// CHECK: @_QPtest_real8
+// CHECK: {{%[A-Za-z0-9._]+}} = "llvm.intr.sin"({{%[A-Za-z0-9._]+}}) : (f64) -> f64
+
+func.func @_QPtest_real4(%arg0: !fir.ref<f32> {fir.bindc_name = "x"}) -> f32 {
+  %0 = fir.alloca f32 {bindc_name = "test_real4", uniq_name = "_QFtest_real4Etest_real4"}
+  %1 = fir.load %arg0 : !fir.ref<f32>
+  %2 = math.sin %1 : f32
+  fir.store %2 to %0 : !fir.ref<f32>
+  %3 = fir.load %0 : !fir.ref<f32>
+  return %3 : f32
+}
+func.func @_QPtest_real8(%arg0: !fir.ref<f64> {fir.bindc_name = "x"}) -> f64 {
+  %0 = fir.alloca f64 {bindc_name = "test_real8", uniq_name = "_QFtest_real8Etest_real8"}
+  %1 = fir.load %arg0 : !fir.ref<f64>
+  %2 = math.sin %1 : f64
+  fir.store %2 to %0 : !fir.ref<f64>
+  %3 = fir.load %0 : !fir.ref<f64>
+  return %3 : f64
+}
+
+//--- sin_relaxed.fir
+// RUN: fir-opt %t/sin_relaxed.fir --fir-to-llvm-ir="target=x86_64-unknown-linux-gnu" | FileCheck %t/sin_relaxed.fir
+// CHECK: @_QPtest_real4
+// CHECK: {{%[A-Za-z0-9._]+}} = "llvm.intr.sin"({{%[A-Za-z0-9._]+}}) : (f32) -> f32
+
+// CHECK: @_QPtest_real8
+// CHECK: {{%[A-Za-z0-9._]+}} = "llvm.intr.sin"({{%[A-Za-z0-9._]+}}) : (f64) -> f64
+
+func.func @_QPtest_real4(%arg0: !fir.ref<f32> {fir.bindc_name = "x"}) -> f32 {
+  %0 = fir.alloca f32 {bindc_name = "test_real4", uniq_name = "_QFtest_real4Etest_real4"}
+  %1 = fir.load %arg0 : !fir.ref<f32>
+  %2 = math.sin %1 : f32
+  fir.store %2 to %0 : !fir.ref<f32>
+  %3 = fir.load %0 : !fir.ref<f32>
+  return %3 : f32
+}
+func.func @_QPtest_real8(%arg0: !fir.ref<f64> {fir.bindc_name = "x"}) -> f64 {
+  %0 = fir.alloca f64 {bindc_name = "test_real8", uniq_name = "_QFtest_real8Etest_real8"}
+  %1 = fir.load %arg0 : !fir.ref<f64>
+  %2 = math.sin %1 : f64
+  fir.store %2 to %0 : !fir.ref<f64>
+  %3 = fir.load %0 : !fir.ref<f64>
+  return %3 : f64
+}
+
+//--- sin_precise.fir
+// RUN: fir-opt %t/sin_precise.fir --fir-to-llvm-ir="target=x86_64-unknown-linux-gnu" | FileCheck %t/sin_precise.fir
+// CHECK: @_QPtest_real4
+// CHECK: {{%[A-Za-z0-9._]+}} = llvm.call @sinf({{%[A-Za-z0-9._]+}}) : (f32) -> f32
+
+// CHECK: @_QPtest_real8
+// CHECK: {{%[A-Za-z0-9._]+}} = llvm.call @sin({{%[A-Za-z0-9._]+}}) : (f64) -> f64
+
+func.func @_QPtest_real4(%arg0: !fir.ref<f32> {fir.bindc_name = "x"}) -> f32 {
+  %0 = fir.alloca f32 {bindc_name = "test_real4", uniq_name = "_QFtest_real4Etest_real4"}
+  %1 = fir.load %arg0 : !fir.ref<f32>
+  %2 = fir.call @sinf(%1) : (f32) -> f32
+  fir.store %2 to %0 : !fir.ref<f32>
+  %3 = fir.load %0 : !fir.ref<f32>
+  return %3 : f32
+}
+func.func @_QPtest_real8(%arg0: !fir.ref<f64> {fir.bindc_name = "x"}) -> f64 {
+  %0 = fir.alloca f64 {bindc_name = "test_real8", uniq_name = "_QFtest_real8Etest_real8"}
+  %1 = fir.load %arg0 : !fir.ref<f64>
+  %2 = fir.call @sin(%1) : (f64) -> f64
+  fir.store %2 to %0 : !fir.ref<f64>
+  %3 = fir.load %0 : !fir.ref<f64>
+  return %3 : f64
+}
+func.func private @sinf(f32) -> f32
+func.func private @sin(f64) -> f64
+
+//--- tanh_fast.fir
+// RUN: fir-opt %t/tanh_fast.fir --fir-to-llvm-ir="target=x86_64-unknown-linux-gnu" | FileCheck %t/tanh_fast.fir
+// CHECK: @_QPtest_real4
+// CHECK: {{%[A-Za-z0-9._]+}} = llvm.call @tanhf({{%[A-Za-z0-9._]+}}) : (f32) -> f32
+
+// CHECK: @_QPtest_real8
+// CHECK: {{%[A-Za-z0-9._]+}} = llvm.call @tanh({{%[A-Za-z0-9._]+}}) : (f64) -> f64
+
+func.func @_QPtest_real4(%arg0: !fir.ref<f32> {fir.bindc_name = "x"}) -> f32 {
+  %0 = fir.alloca f32 {bindc_name = "test_real4", uniq_name = "_QFtest_real4Etest_real4"}
+  %1 = fir.load %arg0 : !fir.ref<f32>
+  %2 = math.tanh %1 : f32
+  fir.store %2 to %0 : !fir.ref<f32>
+  %3 = fir.load %0 : !fir.ref<f32>
+  return %3 : f32
+}
+func.func @_QPtest_real8(%arg0: !fir.ref<f64> {fir.bindc_name = "x"}) -> f64 {
+  %0 = fir.alloca f64 {bindc_name = "test_real8", uniq_name = "_QFtest_real8Etest_real8"}
+  %1 = fir.load %arg0 : !fir.ref<f64>
+  %2 = math.tanh %1 : f64
+  fir.store %2 to %0 : !fir.ref<f64>
+  %3 = fir.load %0 : !fir.ref<f64>
+  return %3 : f64
+}
+
+//--- tanh_relaxed.fir
+// RUN: fir-opt %t/tanh_relaxed.fir --fir-to-llvm-ir="target=x86_64-unknown-linux-gnu" | FileCheck %t/tanh_relaxed.fir
+// CHECK: @_QPtest_real4
+// CHECK: {{%[A-Za-z0-9._]+}} = llvm.call @tanhf({{%[A-Za-z0-9._]+}}) : (f32) -> f32
+
+// CHECK: @_QPtest_real8
+// CHECK: {{%[A-Za-z0-9._]+}} = llvm.call @tanh({{%[A-Za-z0-9._]+}}) : (f64) -> f64
+
+func.func @_QPtest_real4(%arg0: !fir.ref<f32> {fir.bindc_name = "x"}) -> f32 {
+  %0 = fir.alloca f32 {bindc_name = "test_real4", uniq_name = "_QFtest_real4Etest_real4"}
+  %1 = fir.load %arg0 : !fir.ref<f32>
+  %2 = math.tanh %1 : f32
+  fir.store %2 to %0 : !fir.ref<f32>
+  %3 = fir.load %0 : !fir.ref<f32>
+  return %3 : f32
+}
+func.func @_QPtest_real8(%arg0: !fir.ref<f64> {fir.bindc_name = "x"}) -> f64 {
+  %0 = fir.alloca f64 {bindc_name = "test_real8", uniq_name = "_QFtest_real8Etest_real8"}
+  %1 = fir.load %arg0 : !fir.ref<f64>
+  %2 = math.tanh %1 : f64
+  fir.store %2 to %0 : !fir.ref<f64>
+  %3 = fir.load %0 : !fir.ref<f64>
+  return %3 : f64
+}
+
+//--- tanh_precise.fir
+// RUN: fir-opt %t/tanh_precise.fir --fir-to-llvm-ir="target=x86_64-unknown-linux-gnu" | FileCheck %t/tanh_precise.fir
+// CHECK: @_QPtest_real4
+// CHECK: {{%[A-Za-z0-9._]+}} = llvm.call @tanhf({{%[A-Za-z0-9._]+}}) : (f32) -> f32
+
+// CHECK: @_QPtest_real8
+// CHECK: {{%[A-Za-z0-9._]+}} = llvm.call @tanh({{%[A-Za-z0-9._]+}}) : (f64) -> f64
+
+func.func @_QPtest_real4(%arg0: !fir.ref<f32> {fir.bindc_name = "x"}) -> f32 {
+  %0 = fir.alloca f32 {bindc_name = "test_real4", uniq_name = "_QFtest_real4Etest_real4"}
+  %1 = fir.load %arg0 : !fir.ref<f32>
+  %2 = fir.call @tanhf(%1) : (f32) -> f32
+  fir.store %2 to %0 : !fir.ref<f32>
+  %3 = fir.load %0 : !fir.ref<f32>
+  return %3 : f32
+}
+func.func @_QPtest_real8(%arg0: !fir.ref<f64> {fir.bindc_name = "x"}) -> f64 {
+  %0 = fir.alloca f64 {bindc_name = "test_real8", uniq_name = "_QFtest_real8Etest_real8"}
+  %1 = fir.load %arg0 : !fir.ref<f64>
+  %2 = fir.call @tanh(%1) : (f64) -> f64
+  fir.store %2 to %0 : !fir.ref<f64>
+  %3 = fir.load %0 : !fir.ref<f64>
+  return %3 : f64
+}
+func.func private @tanhf(f32) -> f32
+func.func private @tanh(f64) -> f64
+

diff  --git a/flang/test/Lower/Intrinsics/exp.f90 b/flang/test/Lower/Intrinsics/exp.f90
index c8778784cbaff..8d7a6358bda35 100644
--- a/flang/test/Lower/Intrinsics/exp.f90
+++ b/flang/test/Lower/Intrinsics/exp.f90
@@ -1,5 +1,5 @@
-! RUN: bbc -emit-fir %s -o - | FileCheck %s
-! RUN: %flang_fc1 -emit-fir %s -o - | FileCheck %s
+! RUN: bbc -emit-fir -outline-intrinsics %s -o - | FileCheck %s
+! RUN: %flang_fc1 -emit-fir -mllvm -outline-intrinsics %s -o - | FileCheck %s
 
 ! CHECK-LABEL: exp_testr
 ! CHECK-SAME: (%[[AREF:.*]]: !fir.ref<f32> {{.*}}, %[[BREF:.*]]: !fir.ref<f32> {{.*}})

diff  --git a/flang/test/Lower/Intrinsics/log.f90 b/flang/test/Lower/Intrinsics/log.f90
index ae5f21ca96f69..c8d13ef71c202 100644
--- a/flang/test/Lower/Intrinsics/log.f90
+++ b/flang/test/Lower/Intrinsics/log.f90
@@ -1,5 +1,5 @@
-! RUN: bbc -emit-fir %s -o - | FileCheck %s
-! RUN: %flang_fc1 -emit-fir %s -o - | FileCheck %s
+! RUN: bbc -emit-fir -outline-intrinsics %s -o - | FileCheck %s
+! RUN: %flang_fc1 -emit-fir -mllvm -outline-intrinsics %s -o - | FileCheck %s
 
 ! CHECK-LABEL: log_testr
 ! CHECK-SAME: (%[[AREF:.*]]: !fir.ref<f32> {{.*}}, %[[BREF:.*]]: !fir.ref<f32> {{.*}})

diff  --git a/flang/test/Lower/Intrinsics/math-runtime-options.f90 b/flang/test/Lower/Intrinsics/math-runtime-options.f90
index f2439cef14ed0..e9daf26051d5d 100644
--- a/flang/test/Lower/Intrinsics/math-runtime-options.f90
+++ b/flang/test/Lower/Intrinsics/math-runtime-options.f90
@@ -1,7 +1,11 @@
-! RUN: bbc -emit-fir --math-runtime=fast %s -o - | FileCheck %s --check-prefixes="FIR,FAST"
-! RUN: bbc -emit-fir --math-runtime=relaxed %s -o - | FileCheck %s --check-prefixes="FIR,RELAXED"
-! RUN: bbc -emit-fir --math-runtime=precise %s -o - | FileCheck %s --check-prefixes="FIR,PRECISE"
-! RUN: bbc -emit-fir --math-runtime=llvm %s -o - | FileCheck %s --check-prefixes="FIR,LLVM"
+! RUN: bbc -emit-fir --math-runtime=fast -outline-intrinsics %s -o - | FileCheck %s --check-prefixes="FIR,FAST"
+! RUN: %flang_fc1 -emit-fir -mllvm -math-runtime=fast -mllvm -outline-intrinsics %s -o - | FileCheck %s --check-prefixes="FIR,FAST"
+! RUN: bbc -emit-fir --math-runtime=relaxed -outline-intrinsics %s -o - | FileCheck %s --check-prefixes="FIR,RELAXED"
+! RUN: %flang_fc1 -emit-fir -mllvm -math-runtime=relaxed -mllvm -outline-intrinsics %s -o - | FileCheck %s --check-prefixes="FIR,RELAXED"
+! RUN: bbc -emit-fir --math-runtime=precise -outline-intrinsics %s -o - | FileCheck %s --check-prefixes="FIR,PRECISE"
+! RUN: %flang_fc1 -emit-fir -mllvm -math-runtime=precise -mllvm -outline-intrinsics %s -o - | FileCheck %s --check-prefixes="FIR,PRECISE"
+! RUN: bbc -emit-fir --math-runtime=llvm -outline-intrinsics %s -o - | FileCheck %s --check-prefixes="FIR,LLVM"
+! RUN: %flang_fc1 -emit-fir -mllvm -math-runtime=llvm -mllvm -outline-intrinsics %s -o - | FileCheck %s --check-prefixes="FIR,LLVM"
 
 ! CHECK-LABEL: cos_testr
 subroutine cos_testr(a, b)

diff  --git a/flang/test/Lower/array-expression-slice-1.f90 b/flang/test/Lower/array-expression-slice-1.f90
index 30f17de23c04b..6a51ffdfbfb8e 100644
--- a/flang/test/Lower/array-expression-slice-1.f90
+++ b/flang/test/Lower/array-expression-slice-1.f90
@@ -1,4 +1,4 @@
-! RUN: bbc -o - %s | FileCheck %s
+! RUN: bbc -o - --outline-intrinsics %s | FileCheck %s
 
 ! CHECK-LABEL: func @_QQmain() {
 ! CHECK-DAG:         %[[VAL_0:.*]] = arith.constant 10 : index

diff  --git a/flang/test/Lower/late-math-lowering.f90 b/flang/test/Lower/late-math-lowering.f90
new file mode 100644
index 0000000000000..7d958d11a96ff
--- /dev/null
+++ b/flang/test/Lower/late-math-lowering.f90
@@ -0,0 +1,497 @@
+! RUN: split-file %s %t
+
+//--- abs.f90
+! RUN: bbc -emit-fir %t/abs.f90 -o - --lower-math-early=false --math-runtime=fast | FileCheck --check-prefixes=ALL,FAST %t/abs.f90
+! RUN: %flang_fc1 -emit-fir -mllvm -lower-math-early=false -mllvm -math-runtime=fast %t/abs.f90 -o - | FileCheck --check-prefixes=ALL,FAST %t/abs.f90
+! RUN: bbc -emit-fir %t/abs.f90 -o - --lower-math-early=false --math-runtime=relaxed | FileCheck --check-prefixes=ALL,RELAXED %t/abs.f90
+! RUN: %flang_fc1 -emit-fir -mllvm -lower-math-early=false -mllvm -math-runtime=relaxed %t/abs.f90 -o - | FileCheck --check-prefixes=ALL,RELAXED %t/abs.f90
+! RUN: bbc -emit-fir %t/abs.f90 -o - --lower-math-early=false --math-runtime=precise | FileCheck --check-prefixes=ALL,PRECISE %t/abs.f90
+! RUN: %flang_fc1 -emit-fir -mllvm -lower-math-early=false -mllvm -math-runtime=precise %t/abs.f90 -o - | FileCheck --check-prefixes=ALL,PRECISE %t/abs.f90
+
+function test_real4(x)
+  real :: x, test_real4
+  test_real4 = abs(x)
+end function
+
+! ALL-LABEL: @_QPtest_real4
+! FAST: {{%[A-Za-z0-9._]+}} = math.abs {{%[A-Za-z0-9._]+}} : f32
+! RELAXED: {{%[A-Za-z0-9._]+}} = math.abs {{%[A-Za-z0-9._]+}} : f32
+! PRECISE: {{%[A-Za-z0-9._]+}} = fir.call @fabsf({{%[A-Za-z0-9._]+}}) : (f32) -> f32
+
+function test_real8(x)
+  real(8) :: x, test_real8
+  test_real8 = abs(x)
+end function
+
+! ALL-LABEL: @_QPtest_real8
+! FAST: {{%[A-Za-z0-9._]+}} = math.abs {{%[A-Za-z0-9._]+}} : f64
+! RELAXED: {{%[A-Za-z0-9._]+}} = math.abs {{%[A-Za-z0-9._]+}} : f64
+! PRECISE: {{%[A-Za-z0-9._]+}} = fir.call @fabs({{%[A-Za-z0-9._]+}}) : (f64) -> f64
+
+function test_complex4(c)
+  complex(4) :: c, test_complex4
+  test_complex4 = abs(c)
+end function
+
+! ALL-LABEL: @_QPtest_complex4
+! ALL: {{%[A-Za-z0-9._]+}} = fir.call @hypotf({{%[A-Za-z0-9._]+}}, {{%[A-Za-z0-9._]+}}) : (f32, f32) -> f32
+
+function test_complex8(c)
+  complex(8) :: c, test_complex8
+  test_complex8 = abs(c)
+end function
+
+! ALL-LABEL: @_QPtest_complex8
+! ALL: {{%[A-Za-z0-9._]+}} = fir.call @hypot({{%[A-Za-z0-9._]+}}, {{%[A-Za-z0-9._]+}}) : (f64, f64) -> f64
+
+//--- aint.f90
+! RUN: bbc -emit-fir %t/aint.f90 -o - --lower-math-early=false --math-runtime=fast | FileCheck --check-prefixes=ALL %t/aint.f90
+! RUN: %flang_fc1 -emit-fir -mllvm -lower-math-early=false -mllvm -math-runtime=fast %t/aint.f90 -o - | FileCheck --check-prefixes=ALL %t/aint.f90
+! RUN: bbc -emit-fir %t/aint.f90 -o - --lower-math-early=false --math-runtime=relaxed | FileCheck --check-prefixes=ALL %t/aint.f90
+! RUN: %flang_fc1 -emit-fir -mllvm -lower-math-early=false -mllvm -math-runtime=relaxed %t/aint.f90 -o - | FileCheck --check-prefixes=ALL %t/aint.f90
+! RUN: bbc -emit-fir %t/aint.f90 -o - --lower-math-early=false --math-runtime=precise | FileCheck --check-prefixes=ALL %t/aint.f90
+! RUN: %flang_fc1 -emit-fir -mllvm -lower-math-early=false -mllvm -math-runtime=precise %t/aint.f90 -o - | FileCheck --check-prefixes=ALL %t/aint.f90
+
+function test_real4(x)
+  real :: x, test_real4
+  test_real4 = aint(x)
+end function
+
+! ALL-LABEL: @_QPtest_real4
+! ALL: {{%[A-Za-z0-9._]+}} = fir.call @llvm.trunc.f32({{%[A-Za-z0-9._]+}}) : (f32) -> f32
+
+function test_real8(x)
+  real(8) :: x, test_real8
+  test_real8 = aint(x)
+end function
+
+! ALL-LABEL: @_QPtest_real8
+! ALL: {{%[A-Za-z0-9._]+}} = fir.call @llvm.trunc.f64({{%[A-Za-z0-9._]+}}) : (f64) -> f64
+
+//--- anint.f90
+! RUN: bbc -emit-fir %t/anint.f90 -o - --lower-math-early=false --math-runtime=fast | FileCheck --check-prefixes=ALL,FAST %t/anint.f90
+! RUN: %flang_fc1 -emit-fir -mllvm -lower-math-early=false -mllvm -math-runtime=fast %t/anint.f90 -o - | FileCheck --check-prefixes=ALL,FAST %t/anint.f90
+! RUN: bbc -emit-fir %t/anint.f90 -o - --lower-math-early=false --math-runtime=relaxed | FileCheck --check-prefixes=ALL,RELAXED %t/anint.f90
+! RUN: %flang_fc1 -emit-fir -mllvm -lower-math-early=false -mllvm -math-runtime=relaxed %t/anint.f90 -o - | FileCheck --check-prefixes=ALL,RELAXED %t/anint.f90
+! RUN: bbc -emit-fir %t/anint.f90 -o - --lower-math-early=false --math-runtime=precise | FileCheck --check-prefixes=ALL,PRECISE %t/anint.f90
+! RUN: %flang_fc1 -emit-fir -mllvm -lower-math-early=false -mllvm -math-runtime=precise %t/anint.f90 -o - | FileCheck --check-prefixes=ALL,PRECISE %t/anint.f90
+
+function test_real4(x)
+  real :: x, test_real4
+  test_real4 = anint(x)
+end function
+
+! ALL-LABEL: @_QPtest_real4
+! FAST: {{%[A-Za-z0-9._]+}} = "llvm.intr.round"({{%[A-Za-z0-9._]+}}) : (f32) -> f32
+! RELAXED: {{%[A-Za-z0-9._]+}} = "llvm.intr.round"({{%[A-Za-z0-9._]+}}) : (f32) -> f32
+! PRECISE: {{%[A-Za-z0-9._]+}} = fir.call @llvm.round.f32({{%[A-Za-z0-9._]+}}) : (f32) -> f32
+
+function test_real8(x)
+  real(8) :: x, test_real8
+  test_real8 = anint(x)
+end function
+
+! ALL-LABEL: @_QPtest_real8
+! FAST: {{%[A-Za-z0-9._]+}} = "llvm.intr.round"({{%[A-Za-z0-9._]+}}) : (f64) -> f64
+! RELAXED: {{%[A-Za-z0-9._]+}} = "llvm.intr.round"({{%[A-Za-z0-9._]+}}) : (f64) -> f64
+! PRECISE: {{%[A-Za-z0-9._]+}} = fir.call @llvm.round.f64({{%[A-Za-z0-9._]+}}) : (f64) -> f64
+
+//--- atan.f90
+! RUN: bbc -emit-fir %t/atan.f90 -o - --lower-math-early=false --math-runtime=fast | FileCheck --check-prefixes=ALL,FAST %t/atan.f90
+! RUN: %flang_fc1 -emit-fir -mllvm -lower-math-early=false -mllvm -math-runtime=fast %t/atan.f90 -o - | FileCheck --check-prefixes=ALL,FAST %t/atan.f90
+! RUN: bbc -emit-fir %t/atan.f90 -o - --lower-math-early=false --math-runtime=relaxed | FileCheck --check-prefixes=ALL,RELAXED %t/atan.f90
+! RUN: %flang_fc1 -emit-fir -mllvm -lower-math-early=false -mllvm -math-runtime=relaxed %t/atan.f90 -o - | FileCheck --check-prefixes=ALL,RELAXED %t/atan.f90
+! RUN: bbc -emit-fir %t/atan.f90 -o - --lower-math-early=false --math-runtime=precise | FileCheck --check-prefixes=ALL,PRECISE %t/atan.f90
+! RUN: %flang_fc1 -emit-fir -mllvm -lower-math-early=false -mllvm -math-runtime=precise %t/atan.f90 -o - | FileCheck --check-prefixes=ALL,PRECISE %t/atan.f90
+
+function test_real4(x)
+  real :: x, test_real4
+  test_real4 = atan(x)
+end function
+
+! ALL-LABEL: @_QPtest_real4
+! FAST: {{%[A-Za-z0-9._]+}} = math.atan {{%[A-Za-z0-9._]+}} : f32
+! RELAXED: {{%[A-Za-z0-9._]+}} = math.atan {{%[A-Za-z0-9._]+}} : f32
+! PRECISE: {{%[A-Za-z0-9._]+}} = fir.call @atanf({{%[A-Za-z0-9._]+}}) : (f32) -> f32
+
+function test_real8(x)
+  real(8) :: x, test_real8
+  test_real8 = atan(x)
+end function
+
+! ALL-LABEL: @_QPtest_real8
+! FAST: {{%[A-Za-z0-9._]+}} = math.atan {{%[A-Za-z0-9._]+}} : f64
+! RELAXED: {{%[A-Za-z0-9._]+}} = math.atan {{%[A-Za-z0-9._]+}} : f64
+! PRECISE: {{%[A-Za-z0-9._]+}} = fir.call @atan({{%[A-Za-z0-9._]+}}) : (f64) -> f64
+
+//--- atan2.f90
+! RUN: bbc -emit-fir %t/atan2.f90 -o - --lower-math-early=false --math-runtime=fast | FileCheck --check-prefixes=ALL,FAST %t/atan2.f90
+! RUN: %flang_fc1 -emit-fir -mllvm -lower-math-early=false -mllvm -math-runtime=fast %t/atan2.f90 -o - | FileCheck --check-prefixes=ALL,FAST %t/atan2.f90
+! RUN: bbc -emit-fir %t/atan2.f90 -o - --lower-math-early=false --math-runtime=relaxed | FileCheck --check-prefixes=ALL,RELAXED %t/atan2.f90
+! RUN: %flang_fc1 -emit-fir -mllvm -lower-math-early=false -mllvm -math-runtime=relaxed %t/atan2.f90 -o - | FileCheck --check-prefixes=ALL,RELAXED %t/atan2.f90
+! RUN: bbc -emit-fir %t/atan2.f90 -o - --lower-math-early=false --math-runtime=precise | FileCheck --check-prefixes=ALL,PRECISE %t/atan2.f90
+! RUN: %flang_fc1 -emit-fir -mllvm -lower-math-early=false -mllvm -math-runtime=precise %t/atan2.f90 -o - | FileCheck --check-prefixes=ALL,PRECISE %t/atan2.f90
+
+function test_real4(x, y)
+  real :: x, y, test_real4
+  test_real4 = atan2(x, y)
+end function
+
+! ALL-LABEL: @_QPtest_real4
+! FAST: {{%[A-Za-z0-9._]+}} = math.atan2 {{%[A-Za-z0-9._]+}}, {{%[A-Za-z0-9._]+}} : f32
+! RELAXED: {{%[A-Za-z0-9._]+}} = math.atan2 {{%[A-Za-z0-9._]+}}, {{%[A-Za-z0-9._]+}} : f32
+! PRECISE: {{%[A-Za-z0-9._]+}} = fir.call @atan2f({{%[A-Za-z0-9._]+}}, {{%[A-Za-z0-9._]+}}) : (f32, f32) -> f32
+
+function test_real8(x, y)
+  real(8) :: x, y, test_real8
+  test_real8 = atan2(x, y)
+end function
+
+! ALL-LABEL: @_QPtest_real8
+! FAST: {{%[A-Za-z0-9._]+}} = math.atan2 {{%[A-Za-z0-9._]+}}, {{%[A-Za-z0-9._]+}} : f64
+! RELAXED: {{%[A-Za-z0-9._]+}} = math.atan2 {{%[A-Za-z0-9._]+}}, {{%[A-Za-z0-9._]+}} : f64
+! PRECISE: {{%[A-Za-z0-9._]+}} = fir.call @atan2({{%[A-Za-z0-9._]+}}, {{%[A-Za-z0-9._]+}}) : (f64, f64) -> f64
+
+//--- ceiling.f90
+! RUN: bbc -emit-fir %t/ceiling.f90 -o - --lower-math-early=false --math-runtime=fast | FileCheck --check-prefixes=ALL,FAST %t/ceiling.f90
+! RUN: %flang_fc1 -emit-fir -mllvm -lower-math-early=false -mllvm -math-runtime=fast %t/ceiling.f90 -o - | FileCheck --check-prefixes=ALL,FAST %t/ceiling.f90
+! RUN: bbc -emit-fir %t/ceiling.f90 -o - --lower-math-early=false --math-runtime=relaxed | FileCheck --check-prefixes=ALL,RELAXED %t/ceiling.f90
+! RUN: %flang_fc1 -emit-fir -mllvm -lower-math-early=false -mllvm -math-runtime=relaxed %t/ceiling.f90 -o - | FileCheck --check-prefixes=ALL,RELAXED %t/ceiling.f90
+! RUN: bbc -emit-fir %t/ceiling.f90 -o - --lower-math-early=false --math-runtime=precise | FileCheck --check-prefixes=ALL,PRECISE %t/ceiling.f90
+! RUN: %flang_fc1 -emit-fir -mllvm -lower-math-early=false -mllvm -math-runtime=precise %t/ceiling.f90 -o - | FileCheck --check-prefixes=ALL,PRECISE %t/ceiling.f90
+
+function test_real4(x)
+  real :: x, test_real4
+  test_real4 = ceiling(x)
+end function
+
+! ALL-LABEL: @_QPtest_real4
+! FAST: {{%[A-Za-z0-9._]+}} = math.ceil {{%[A-Za-z0-9._]+}} : f32
+! RELAXED: {{%[A-Za-z0-9._]+}} = math.ceil {{%[A-Za-z0-9._]+}} : f32
+! PRECISE: {{%[A-Za-z0-9._]+}} = fir.call @ceilf({{%[A-Za-z0-9._]+}}) : (f32) -> f32
+
+function test_real8(x)
+  real(8) :: x, test_real8
+  test_real8 = ceiling(x)
+end function
+
+! ALL-LABEL: @_QPtest_real8
+! FAST: {{%[A-Za-z0-9._]+}} = math.ceil {{%[A-Za-z0-9._]+}} : f64
+! RELAXED: {{%[A-Za-z0-9._]+}} = math.ceil {{%[A-Za-z0-9._]+}} : f64
+! PRECISE: {{%[A-Za-z0-9._]+}} = fir.call @ceil({{%[A-Za-z0-9._]+}}) : (f64) -> f64
+
+//--- cos.f90
+! RUN: bbc -emit-fir %t/cos.f90 -o - --lower-math-early=false --math-runtime=fast | FileCheck --check-prefixes=ALL,FAST %t/cos.f90
+! RUN: %flang_fc1 -emit-fir -mllvm -lower-math-early=false -mllvm -math-runtime=fast %t/cos.f90 -o - | FileCheck --check-prefixes=ALL,FAST %t/cos.f90
+! RUN: bbc -emit-fir %t/cos.f90 -o - --lower-math-early=false --math-runtime=relaxed | FileCheck --check-prefixes=ALL,RELAXED %t/cos.f90
+! RUN: %flang_fc1 -emit-fir -mllvm -lower-math-early=false -mllvm -math-runtime=relaxed %t/cos.f90 -o - | FileCheck --check-prefixes=ALL,RELAXED %t/cos.f90
+! RUN: bbc -emit-fir %t/cos.f90 -o - --lower-math-early=false --math-runtime=precise | FileCheck --check-prefixes=ALL,PRECISE %t/cos.f90
+! RUN: %flang_fc1 -emit-fir -mllvm -lower-math-early=false -mllvm -math-runtime=precise %t/cos.f90 -o - | FileCheck --check-prefixes=ALL,PRECISE %t/cos.f90
+
+function test_real4(x)
+  real :: x, test_real4
+  test_real4 = cos(x)
+end function
+
+! ALL-LABEL: @_QPtest_real4
+! FAST: {{%[A-Za-z0-9._]+}} = math.cos {{%[A-Za-z0-9._]+}} : f32
+! RELAXED: {{%[A-Za-z0-9._]+}} = math.cos {{%[A-Za-z0-9._]+}} : f32
+! PRECISE: {{%[A-Za-z0-9._]+}} = fir.call @cosf({{%[A-Za-z0-9._]+}}) : (f32) -> f32
+
+function test_real8(x)
+  real(8) :: x, test_real8
+  test_real8 = cos(x)
+end function
+
+! ALL-LABEL: @_QPtest_real8
+! FAST: {{%[A-Za-z0-9._]+}} = math.cos {{%[A-Za-z0-9._]+}} : f64
+! RELAXED: {{%[A-Za-z0-9._]+}} = math.cos {{%[A-Za-z0-9._]+}} : f64
+! PRECISE: {{%[A-Za-z0-9._]+}} = fir.call @cos({{%[A-Za-z0-9._]+}}) : (f64) -> f64
+
+//--- erf.f90
+! RUN: bbc -emit-fir %t/erf.f90 -o - --lower-math-early=false --math-runtime=fast | FileCheck --check-prefixes=ALL,FAST %t/erf.f90
+! RUN: %flang_fc1 -emit-fir -mllvm -lower-math-early=false -mllvm -math-runtime=fast %t/erf.f90 -o - | FileCheck --check-prefixes=ALL,FAST %t/erf.f90
+! RUN: bbc -emit-fir %t/erf.f90 -o - --lower-math-early=false --math-runtime=relaxed | FileCheck --check-prefixes=ALL,RELAXED %t/erf.f90
+! RUN: %flang_fc1 -emit-fir -mllvm -lower-math-early=false -mllvm -math-runtime=relaxed %t/erf.f90 -o - | FileCheck --check-prefixes=ALL,RELAXED %t/erf.f90
+! RUN: bbc -emit-fir %t/erf.f90 -o - --lower-math-early=false --math-runtime=precise | FileCheck --check-prefixes=ALL,PRECISE %t/erf.f90
+! RUN: %flang_fc1 -emit-fir -mllvm -lower-math-early=false -mllvm -math-runtime=precise %t/erf.f90 -o - | FileCheck --check-prefixes=ALL,PRECISE %t/erf.f90
+
+function test_real4(x)
+  real :: x, test_real4
+  test_real4 = erf(x)
+end function
+
+! ALL-LABEL: @_QPtest_real4
+! FAST: {{%[A-Za-z0-9._]+}} = math.erf {{%[A-Za-z0-9._]+}} : f32
+! RELAXED: {{%[A-Za-z0-9._]+}} = math.erf {{%[A-Za-z0-9._]+}} : f32
+! PRECISE: {{%[A-Za-z0-9._]+}} = fir.call @erff({{%[A-Za-z0-9._]+}}) : (f32) -> f32
+
+function test_real8(x)
+  real(8) :: x, test_real8
+  test_real8 = erf(x)
+end function
+
+! ALL-LABEL: @_QPtest_real8
+! FAST: {{%[A-Za-z0-9._]+}} = math.erf {{%[A-Za-z0-9._]+}} : f64
+! RELAXED: {{%[A-Za-z0-9._]+}} = math.erf {{%[A-Za-z0-9._]+}} : f64
+! PRECISE: {{%[A-Za-z0-9._]+}} = fir.call @erf({{%[A-Za-z0-9._]+}}) : (f64) -> f64
+
+//--- exp.f90
+! RUN: bbc -emit-fir %t/exp.f90 -o - --lower-math-early=false --math-runtime=fast | FileCheck --check-prefixes=ALL,FAST %t/exp.f90
+! RUN: %flang_fc1 -emit-fir -mllvm -lower-math-early=false -mllvm -math-runtime=fast %t/exp.f90 -o - | FileCheck --check-prefixes=ALL,FAST %t/exp.f90
+! RUN: bbc -emit-fir %t/exp.f90 -o - --lower-math-early=false --math-runtime=relaxed | FileCheck --check-prefixes=ALL,RELAXED %t/exp.f90
+! RUN: %flang_fc1 -emit-fir -mllvm -lower-math-early=false -mllvm -math-runtime=relaxed %t/exp.f90 -o - | FileCheck --check-prefixes=ALL,RELAXED %t/exp.f90
+! RUN: bbc -emit-fir %t/exp.f90 -o - --lower-math-early=false --math-runtime=precise | FileCheck --check-prefixes=ALL,PRECISE %t/exp.f90
+! RUN: %flang_fc1 -emit-fir -mllvm -lower-math-early=false -mllvm -math-runtime=precise %t/exp.f90 -o - | FileCheck --check-prefixes=ALL,PRECISE %t/exp.f90
+
+function test_real4(x)
+  real :: x, test_real4
+  test_real4 = exp(x)
+end function
+
+! ALL-LABEL: @_QPtest_real4
+! FAST: {{%[A-Za-z0-9._]+}} = math.exp {{%[A-Za-z0-9._]+}} : f32
+! RELAXED: {{%[A-Za-z0-9._]+}} = math.exp {{%[A-Za-z0-9._]+}} : f32
+! PRECISE: {{%[A-Za-z0-9._]+}} = fir.call @expf({{%[A-Za-z0-9._]+}}) : (f32) -> f32
+
+function test_real8(x)
+  real(8) :: x, test_real8
+  test_real8 = exp(x)
+end function
+
+! ALL-LABEL: @_QPtest_real8
+! FAST: {{%[A-Za-z0-9._]+}} = math.exp {{%[A-Za-z0-9._]+}} : f64
+! RELAXED: {{%[A-Za-z0-9._]+}} = math.exp {{%[A-Za-z0-9._]+}} : f64
+! PRECISE: {{%[A-Za-z0-9._]+}} = fir.call @exp({{%[A-Za-z0-9._]+}}) : (f64) -> f64
+
+//--- floor.f90
+! RUN: bbc -emit-fir %t/floor.f90 -o - --lower-math-early=false --math-runtime=fast | FileCheck --check-prefixes=ALL,FAST %t/floor.f90
+! RUN: %flang_fc1 -emit-fir -mllvm -lower-math-early=false -mllvm -math-runtime=fast %t/floor.f90 -o - | FileCheck --check-prefixes=ALL,FAST %t/floor.f90
+! RUN: bbc -emit-fir %t/floor.f90 -o - --lower-math-early=false --math-runtime=relaxed | FileCheck --check-prefixes=ALL,RELAXED %t/floor.f90
+! RUN: %flang_fc1 -emit-fir -mllvm -lower-math-early=false -mllvm -math-runtime=relaxed %t/floor.f90 -o - | FileCheck --check-prefixes=ALL,RELAXED %t/floor.f90
+! RUN: bbc -emit-fir %t/floor.f90 -o - --lower-math-early=false --math-runtime=precise | FileCheck --check-prefixes=ALL,PRECISE %t/floor.f90
+! RUN: %flang_fc1 -emit-fir -mllvm -lower-math-early=false -mllvm -math-runtime=precise %t/floor.f90 -o - | FileCheck --check-prefixes=ALL,PRECISE %t/floor.f90
+
+function test_real4(x)
+  real :: x, test_real4
+  test_real4 = floor(x)
+end function
+
+! ALL-LABEL: @_QPtest_real4
+! FAST: {{%[A-Za-z0-9._]+}} = math.floor {{%[A-Za-z0-9._]+}} : f32
+! RELAXED: {{%[A-Za-z0-9._]+}} = math.floor {{%[A-Za-z0-9._]+}} : f32
+! PRECISE: {{%[A-Za-z0-9._]+}} = fir.call @floorf({{%[A-Za-z0-9._]+}}) : (f32) -> f32
+
+function test_real8(x)
+  real(8) :: x, test_real8
+  test_real8 = floor(x)
+end function
+
+! ALL-LABEL: @_QPtest_real8
+! FAST: {{%[A-Za-z0-9._]+}} = math.floor {{%[A-Za-z0-9._]+}} : f64
+! RELAXED: {{%[A-Za-z0-9._]+}} = math.floor {{%[A-Za-z0-9._]+}} : f64
+! PRECISE: {{%[A-Za-z0-9._]+}} = fir.call @floor({{%[A-Za-z0-9._]+}}) : (f64) -> f64
+
+//--- log.f90
+! RUN: bbc -emit-fir %t/log.f90 -o - --lower-math-early=false --math-runtime=fast | FileCheck --check-prefixes=ALL,FAST %t/log.f90
+! RUN: %flang_fc1 -emit-fir -mllvm -lower-math-early=false -mllvm -math-runtime=fast %t/log.f90 -o - | FileCheck --check-prefixes=ALL,FAST %t/log.f90
+! RUN: bbc -emit-fir %t/log.f90 -o - --lower-math-early=false --math-runtime=relaxed | FileCheck --check-prefixes=ALL,RELAXED %t/log.f90
+! RUN: %flang_fc1 -emit-fir -mllvm -lower-math-early=false -mllvm -math-runtime=relaxed %t/log.f90 -o - | FileCheck --check-prefixes=ALL,RELAXED %t/log.f90
+! RUN: bbc -emit-fir %t/log.f90 -o - --lower-math-early=false --math-runtime=precise | FileCheck --check-prefixes=ALL,PRECISE %t/log.f90
+! RUN: %flang_fc1 -emit-fir -mllvm -lower-math-early=false -mllvm -math-runtime=precise %t/log.f90 -o - | FileCheck --check-prefixes=ALL,PRECISE %t/log.f90
+
+function test_real4(x)
+  real :: x, test_real4
+  test_real4 = log(x)
+end function
+
+! ALL-LABEL: @_QPtest_real4
+! FAST: {{%[A-Za-z0-9._]+}} = math.log {{%[A-Za-z0-9._]+}} : f32
+! RELAXED: {{%[A-Za-z0-9._]+}} = math.log {{%[A-Za-z0-9._]+}} : f32
+! PRECISE: {{%[A-Za-z0-9._]+}} = fir.call @logf({{%[A-Za-z0-9._]+}}) : (f32) -> f32
+
+function test_real8(x)
+  real(8) :: x, test_real8
+  test_real8 = log(x)
+end function
+
+! ALL-LABEL: @_QPtest_real8
+! FAST: {{%[A-Za-z0-9._]+}} = math.log {{%[A-Za-z0-9._]+}} : f64
+! RELAXED: {{%[A-Za-z0-9._]+}} = math.log {{%[A-Za-z0-9._]+}} : f64
+! PRECISE: {{%[A-Za-z0-9._]+}} = fir.call @log({{%[A-Za-z0-9._]+}}) : (f64) -> f64
+
+//--- log10.f90
+! RUN: bbc -emit-fir %t/log10.f90 -o - --lower-math-early=false --math-runtime=fast | FileCheck --check-prefixes=ALL,FAST %t/log10.f90
+! RUN: %flang_fc1 -emit-fir -mllvm -lower-math-early=false -mllvm -math-runtime=fast %t/log10.f90 -o - | FileCheck --check-prefixes=ALL,FAST %t/log10.f90
+! RUN: bbc -emit-fir %t/log10.f90 -o - --lower-math-early=false --math-runtime=relaxed | FileCheck --check-prefixes=ALL,RELAXED %t/log10.f90
+! RUN: %flang_fc1 -emit-fir -mllvm -lower-math-early=false -mllvm -math-runtime=relaxed %t/log10.f90 -o - | FileCheck --check-prefixes=ALL,RELAXED %t/log10.f90
+! RUN: bbc -emit-fir %t/log10.f90 -o - --lower-math-early=false --math-runtime=precise | FileCheck --check-prefixes=ALL,PRECISE %t/log10.f90
+! RUN: %flang_fc1 -emit-fir -mllvm -lower-math-early=false -mllvm -math-runtime=precise %t/log10.f90 -o - | FileCheck --check-prefixes=ALL,PRECISE %t/log10.f90
+
+function test_real4(x)
+  real :: x, test_real4
+  test_real4 = log10(x)
+end function
+
+! ALL-LABEL: @_QPtest_real4
+! FAST: {{%[A-Za-z0-9._]+}} = math.log10 {{%[A-Za-z0-9._]+}} : f32
+! RELAXED: {{%[A-Za-z0-9._]+}} = math.log10 {{%[A-Za-z0-9._]+}} : f32
+! PRECISE: {{%[A-Za-z0-9._]+}} = fir.call @log10f({{%[A-Za-z0-9._]+}}) : (f32) -> f32
+
+function test_real8(x)
+  real(8) :: x, test_real8
+  test_real8 = log10(x)
+end function
+
+! ALL-LABEL: @_QPtest_real8
+! FAST: {{%[A-Za-z0-9._]+}} = math.log10 {{%[A-Za-z0-9._]+}} : f64
+! RELAXED: {{%[A-Za-z0-9._]+}} = math.log10 {{%[A-Za-z0-9._]+}} : f64
+! PRECISE: {{%[A-Za-z0-9._]+}} = fir.call @log10({{%[A-Za-z0-9._]+}}) : (f64) -> f64
+
+//--- nint.f90
+! RUN: bbc -emit-fir %t/nint.f90 -o - --lower-math-early=false --math-runtime=fast | FileCheck --check-prefixes=ALL %t/nint.f90
+! RUN: %flang_fc1 -emit-fir -mllvm -lower-math-early=false -mllvm -math-runtime=fast %t/nint.f90 -o - | FileCheck --check-prefixes=ALL %t/nint.f90
+! RUN: bbc -emit-fir %t/nint.f90 -o - --lower-math-early=false --math-runtime=relaxed | FileCheck --check-prefixes=ALL %t/nint.f90
+! RUN: %flang_fc1 -emit-fir -mllvm -lower-math-early=false -mllvm -math-runtime=relaxed %t/nint.f90 -o - | FileCheck --check-prefixes=ALL %t/nint.f90
+! RUN: bbc -emit-fir %t/nint.f90 -o - --lower-math-early=false --math-runtime=precise | FileCheck --check-prefixes=ALL %t/nint.f90
+! RUN: %flang_fc1 -emit-fir -mllvm -lower-math-early=false -mllvm -math-runtime=precise %t/nint.f90 -o - | FileCheck --check-prefixes=ALL %t/nint.f90
+
+function test_real4(x)
+  real :: x, test_real4
+  test_real4 = nint(x, 4) + nint(x, 8)
+end function
+
+! ALL-LABEL: @_QPtest_real4
+! ALL: {{%[A-Za-z0-9._]+}} = fir.call @llvm.lround.i32.f32({{%[A-Za-z0-9._]+}}) : (f32) -> i32
+! ALL: {{%[A-Za-z0-9._]+}} = fir.call @llvm.lround.i64.f32({{%[A-Za-z0-9._]+}}) : (f32) -> i64
+
+function test_real8(x)
+  real(8) :: x, test_real8
+  test_real8 = nint(x, 4) + nint(x, 8)
+end function
+
+! ALL-LABEL: @_QPtest_real8
+! ALL: {{%[A-Za-z0-9._]+}} = fir.call @llvm.lround.i32.f64({{%[A-Za-z0-9._]+}}) : (f64) -> i32
+! ALL: {{%[A-Za-z0-9._]+}} = fir.call @llvm.lround.i64.f64({{%[A-Za-z0-9._]+}}) : (f64) -> i64
+
+//--- exponentiation.f90
+! RUN: bbc -emit-fir %t/exponentiation.f90 -o - --lower-math-early=false --math-runtime=fast | FileCheck --check-prefixes=ALL,FAST %t/exponentiation.f90
+! RUN: %flang_fc1 -emit-fir -mllvm -lower-math-early=false -mllvm -math-runtime=fast %t/exponentiation.f90 -o - | FileCheck --check-prefixes=ALL,FAST %t/exponentiation.f90
+! RUN: bbc -emit-fir %t/exponentiation.f90 -o - --lower-math-early=false --math-runtime=relaxed | FileCheck --check-prefixes=ALL,RELAXED %t/exponentiation.f90
+! RUN: %flang_fc1 -emit-fir -mllvm -lower-math-early=false -mllvm -math-runtime=relaxed %t/exponentiation.f90 -o - | FileCheck --check-prefixes=ALL,RELAXED %t/exponentiation.f90
+! RUN: bbc -emit-fir %t/exponentiation.f90 -o - --lower-math-early=false --math-runtime=precise | FileCheck --check-prefixes=ALL,PRECISE %t/exponentiation.f90
+! RUN: %flang_fc1 -emit-fir -mllvm -lower-math-early=false -mllvm -math-runtime=precise %t/exponentiation.f90 -o - | FileCheck --check-prefixes=ALL,PRECISE %t/exponentiation.f90
+
+function test_real4(x, y, s, i)
+  real :: x, y, test_real4
+  integer(2) :: s
+  integer(4) :: i
+  test_real4 = x ** s + x ** y + x ** i
+end function
+
+! ALL-LABEL: @_QPtest_real4
+! ALL: [[STOI:%[A-Za-z0-9._]+]] = fir.convert {{%[A-Za-z0-9._]+}} : (i16) -> i32
+! ALL: {{%[A-Za-z0-9._]+}} = fir.call @llvm.powi.f32.i32({{%[A-Za-z0-9._]+}}, [[STOI]]) : (f32, i32) -> f32
+! FAST: {{%[A-Za-z0-9._]+}} = math.powf {{%[A-Za-z0-9._]+}}, {{%[A-Za-z0-9._]+}} : f32
+! RELAXED: {{%[A-Za-z0-9._]+}} = math.powf {{%[A-Za-z0-9._]+}}, {{%[A-Za-z0-9._]+}} : f32
+! PRECISE: {{%[A-Za-z0-9._]+}} = fir.call @powf({{%[A-Za-z0-9._]+}}, {{%[A-Za-z0-9._]+}}) : (f32, f32) -> f32
+! ALL: {{%[A-Za-z0-9._]+}} = fir.call @llvm.powi.f32.i32({{%[A-Za-z0-9._]+}}, {{%[A-Za-z0-9._]+}}) : (f32, i32) -> f32
+
+function test_real8(x, y, s, i)
+  real(8) :: x, y, test_real8
+  integer(2) :: s
+  integer(4) :: i
+  test_real8 = x ** s + x ** y + x ** i
+end function
+
+! ALL-LABEL: @_QPtest_real8
+! ALL: [[STOI:%[A-Za-z0-9._]+]] = fir.convert {{%[A-Za-z0-9._]+}} : (i16) -> i32
+! ALL: {{%[A-Za-z0-9._]+}} = fir.call @llvm.powi.f64.i32({{%[A-Za-z0-9._]+}}, [[STOI]]) : (f64, i32) -> f64
+! FAST: {{%[A-Za-z0-9._]+}} = math.powf {{%[A-Za-z0-9._]+}}, {{%[A-Za-z0-9._]+}} : f64
+! RELAXED: {{%[A-Za-z0-9._]+}} = math.powf {{%[A-Za-z0-9._]+}}, {{%[A-Za-z0-9._]+}} : f64
+! PRECISE: {{%[A-Za-z0-9._]+}} = fir.call @pow({{%[A-Za-z0-9._]+}}, {{%[A-Za-z0-9._]+}}) : (f64, f64) -> f64
+! ALL: {{%[A-Za-z0-9._]+}} = fir.call @llvm.powi.f64.i32({{%[A-Za-z0-9._]+}}, {{%[A-Za-z0-9._]+}}) : (f64, i32) -> f64
+
+//--- sign.f90
+! RUN: bbc -emit-fir %t/sign.f90 -o - --lower-math-early=false --math-runtime=fast | FileCheck --check-prefixes=ALL,FAST %t/sign.f90
+! RUN: %flang_fc1 -emit-fir -mllvm -lower-math-early=false -mllvm -math-runtime=fast %t/sign.f90 -o - | FileCheck --check-prefixes=ALL,FAST %t/sign.f90
+! RUN: bbc -emit-fir %t/sign.f90 -o - --lower-math-early=false --math-runtime=relaxed | FileCheck --check-prefixes=ALL,RELAXED %t/sign.f90
+! RUN: %flang_fc1 -emit-fir -mllvm -lower-math-early=false -mllvm -math-runtime=relaxed %t/sign.f90 -o - | FileCheck --check-prefixes=ALL,RELAXED %t/sign.f90
+! RUN: bbc -emit-fir %t/sign.f90 -o - --lower-math-early=false --math-runtime=precise | FileCheck --check-prefixes=ALL,PRECISE %t/sign.f90
+! RUN: %flang_fc1 -emit-fir -mllvm -lower-math-early=false -mllvm -math-runtime=precise %t/sign.f90 -o - | FileCheck --check-prefixes=ALL,PRECISE %t/sign.f90
+
+function test_real4(x, y)
+  real :: x, y, test_real4
+  test_real4 = sign(x, y)
+end function
+
+! ALL-LABEL: @_QPtest_real4
+! FAST: {{%[A-Za-z0-9._]+}} = math.copysign {{%[A-Za-z0-9._]+}}, {{%[A-Za-z0-9._]+}} : f32
+! RELAXED: {{%[A-Za-z0-9._]+}} = math.copysign {{%[A-Za-z0-9._]+}}, {{%[A-Za-z0-9._]+}} : f32
+! PRECISE: {{%[A-Za-z0-9._]+}} = fir.call @copysignf({{%[A-Za-z0-9._]+}}, {{%[A-Za-z0-9._]+}}) : (f32, f32) -> f32
+
+function test_real8(x, y)
+  real(8) :: x, y, test_real8
+  test_real8 = sign(x, y)
+end function
+
+! ALL-LABEL: @_QPtest_real8
+! FAST: {{%[A-Za-z0-9._]+}} = math.copysign {{%[A-Za-z0-9._]+}}, {{%[A-Za-z0-9._]+}} : f64
+! RELAXED: {{%[A-Za-z0-9._]+}} = math.copysign {{%[A-Za-z0-9._]+}}, {{%[A-Za-z0-9._]+}} : f64
+! PRECISE: {{%[A-Za-z0-9._]+}} = fir.call @copysign({{%[A-Za-z0-9._]+}}, {{%[A-Za-z0-9._]+}}) : (f64, f64) -> f64
+
+//--- sin.f90
+! RUN: bbc -emit-fir %t/sin.f90 -o - --lower-math-early=false --math-runtime=fast | FileCheck --check-prefixes=ALL,FAST %t/sin.f90
+! RUN: %flang_fc1 -emit-fir -mllvm -lower-math-early=false -mllvm -math-runtime=fast %t/sin.f90 -o - | FileCheck --check-prefixes=ALL,FAST %t/sin.f90
+! RUN: bbc -emit-fir %t/sin.f90 -o - --lower-math-early=false --math-runtime=relaxed | FileCheck --check-prefixes=ALL,RELAXED %t/sin.f90
+! RUN: %flang_fc1 -emit-fir -mllvm -lower-math-early=false -mllvm -math-runtime=relaxed %t/sin.f90 -o - | FileCheck --check-prefixes=ALL,RELAXED %t/sin.f90
+! RUN: bbc -emit-fir %t/sin.f90 -o - --lower-math-early=false --math-runtime=precise | FileCheck --check-prefixes=ALL,PRECISE %t/sin.f90
+! RUN: %flang_fc1 -emit-fir -mllvm -lower-math-early=false -mllvm -math-runtime=precise %t/sin.f90 -o - | FileCheck --check-prefixes=ALL,PRECISE %t/sin.f90
+
+function test_real4(x)
+  real :: x, test_real4
+  test_real4 = sin(x)
+end function
+
+! ALL-LABEL: @_QPtest_real4
+! FAST: {{%[A-Za-z0-9._]+}} = math.sin {{%[A-Za-z0-9._]+}} : f32
+! RELAXED: {{%[A-Za-z0-9._]+}} = math.sin {{%[A-Za-z0-9._]+}} : f32
+! PRECISE: {{%[A-Za-z0-9._]+}} = fir.call @sinf({{%[A-Za-z0-9._]+}}) : (f32) -> f32
+
+function test_real8(x)
+  real(8) :: x, test_real8
+  test_real8 = sin(x)
+end function
+
+! ALL-LABEL: @_QPtest_real8
+! FAST: {{%[A-Za-z0-9._]+}} = math.sin {{%[A-Za-z0-9._]+}} : f64
+! RELAXED: {{%[A-Za-z0-9._]+}} = math.sin {{%[A-Za-z0-9._]+}} : f64
+! PRECISE: {{%[A-Za-z0-9._]+}} = fir.call @sin({{%[A-Za-z0-9._]+}}) : (f64) -> f64
+
+//--- tanh.f90
+! RUN: bbc -emit-fir %t/tanh.f90 -o - --lower-math-early=false --math-runtime=fast | FileCheck --check-prefixes=ALL,FAST %t/tanh.f90
+! RUN: %flang_fc1 -emit-fir -mllvm -lower-math-early=false -mllvm -math-runtime=fast %t/tanh.f90 -o - | FileCheck --check-prefixes=ALL,FAST %t/tanh.f90
+! RUN: bbc -emit-fir %t/tanh.f90 -o - --lower-math-early=false --math-runtime=relaxed | FileCheck --check-prefixes=ALL,RELAXED %t/tanh.f90
+! RUN: %flang_fc1 -emit-fir -mllvm -lower-math-early=false -mllvm -math-runtime=relaxed %t/tanh.f90 -o - | FileCheck --check-prefixes=ALL,RELAXED %t/tanh.f90
+! RUN: bbc -emit-fir %t/tanh.f90 -o - --lower-math-early=false --math-runtime=precise | FileCheck --check-prefixes=ALL,PRECISE %t/tanh.f90
+! RUN: %flang_fc1 -emit-fir -mllvm -lower-math-early=false -mllvm -math-runtime=precise %t/tanh.f90 -o - | FileCheck --check-prefixes=ALL,PRECISE %t/tanh.f90
+
+function test_real4(x)
+  real :: x, test_real4
+  test_real4 = tanh(x)
+end function
+
+! ALL-LABEL: @_QPtest_real4
+! FAST: {{%[A-Za-z0-9._]+}} = math.tanh {{%[A-Za-z0-9._]+}} : f32
+! RELAXED: {{%[A-Za-z0-9._]+}} = math.tanh {{%[A-Za-z0-9._]+}} : f32
+! PRECISE: {{%[A-Za-z0-9._]+}} = fir.call @tanhf({{%[A-Za-z0-9._]+}}) : (f32) -> f32
+
+function test_real8(x)
+  real(8) :: x, test_real8
+  test_real8 = tanh(x)
+end function
+
+! ALL-LABEL: @_QPtest_real8
+! FAST: {{%[A-Za-z0-9._]+}} = math.tanh {{%[A-Za-z0-9._]+}} : f64
+! RELAXED: {{%[A-Za-z0-9._]+}} = math.tanh {{%[A-Za-z0-9._]+}} : f64
+! PRECISE: {{%[A-Za-z0-9._]+}} = fir.call @tanh({{%[A-Za-z0-9._]+}}) : (f64) -> f64

diff  --git a/flang/test/Lower/llvm-math.f90 b/flang/test/Lower/llvm-math.f90
index f346642830522..8ad4809bb8228 100644
--- a/flang/test/Lower/llvm-math.f90
+++ b/flang/test/Lower/llvm-math.f90
@@ -1,4 +1,5 @@
-! RUN: bbc -emit-fir %s -o - --math-runtime=llvm | FileCheck %s
+! RUN: bbc -emit-fir %s -o - --math-runtime=llvm --outline-intrinsics | FileCheck %s
+! RUN: %flang_fc1 -emit-fir -mllvm -math-runtime=llvm -mllvm -outline-intrinsics %s -o - | FileCheck %s
 
       SUBROUTINE POW_WRAPPER(IN, IN2, OUT)
       DOUBLE PRECISION IN, IN2

diff  --git a/flang/test/Lower/sqrt.f90 b/flang/test/Lower/sqrt.f90
index fe36e86db1a99..d0f13dff1fffe 100644
--- a/flang/test/Lower/sqrt.f90
+++ b/flang/test/Lower/sqrt.f90
@@ -1,5 +1,5 @@
-! RUN: bbc -emit-fir %s -o - | FileCheck %s
-! RUN: %flang_fc1 -emit-fir %s -o - | FileCheck %s
+! RUN: bbc -emit-fir -outline-intrinsics %s -o - | FileCheck %s
+! RUN: %flang_fc1 -emit-fir -mllvm -outline-intrinsics %s -o - | FileCheck %s
 
 ! CHECK-LABEL: sqrt_testr
 subroutine sqrt_testr(a, b)

diff  --git a/flang/test/Lower/trigonometric-intrinsics.f90 b/flang/test/Lower/trigonometric-intrinsics.f90
index 51d6e149df45c..e92d7f4ebd493 100644
--- a/flang/test/Lower/trigonometric-intrinsics.f90
+++ b/flang/test/Lower/trigonometric-intrinsics.f90
@@ -1,5 +1,5 @@
-! RUN: bbc -emit-fir %s -o - | FileCheck %s
-! RUN: %flang_fc1 -emit-fir %s -o - | FileCheck %s
+! RUN: bbc -emit-fir -outline-intrinsics %s -o - | FileCheck %s
+! RUN: %flang_fc1 -emit-fir -mllvm -outline-intrinsics %s -o - | FileCheck %s
 
 ! CHECK-LABEL: atan_testr
 subroutine atan_testr(a, b)


        


More information about the flang-commits mailing list