[flang-commits] [flang] 529d094 - [fir] Add fir numeric intrinsic runtime call builder

Valentin Clement via flang-commits flang-commits at lists.llvm.org
Thu Dec 2 01:22:46 PST 2021


Author: Valentin Clement
Date: 2021-12-02T10:22:26+01:00
New Revision: 529d0942daf3ed0766dafadad562dfeacf734c3e

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

LOG: [fir] Add fir numeric intrinsic runtime call builder

This patch adds the FIR builder to generate the numeric intrinsic
runtime call.

This patch is part of the upstreaming effort from fir-dev branch.

Reviewed By: rovka

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

Co-authored-by: Jean Perier <jperier at nvidia.com>
Co-authored-by: mleair <leairmark at gmail.com>

Added: 
    flang/include/flang/Optimizer/Builder/Runtime/Numeric.h
    flang/lib/Optimizer/Builder/Runtime/Numeric.cpp
    flang/unittests/Optimizer/Builder/Runtime/NumericTest.cpp

Modified: 
    flang/lib/Optimizer/Builder/CMakeLists.txt
    flang/unittests/Optimizer/CMakeLists.txt

Removed: 
    


################################################################################
diff  --git a/flang/include/flang/Optimizer/Builder/Runtime/Numeric.h b/flang/include/flang/Optimizer/Builder/Runtime/Numeric.h
new file mode 100644
index 0000000000000..323cc2ce6d49a
--- /dev/null
+++ b/flang/include/flang/Optimizer/Builder/Runtime/Numeric.h
@@ -0,0 +1,50 @@
+//===-- Numeric.h -- generate numeric intrinsics runtime calls --*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef FORTRAN_OPTIMIZER_BUILDER_RUNTIME_NUMERIC_H
+#define FORTRAN_OPTIMIZER_BUILDER_RUNTIME_NUMERIC_H
+
+#include "mlir/Dialect/StandardOps/IR/Ops.h"
+
+namespace fir {
+class ExtendedValue;
+class FirOpBuilder;
+} // namespace fir
+
+namespace fir::runtime {
+
+/// Generate call to Exponent intrinsic runtime routine.
+mlir::Value genExponent(fir::FirOpBuilder &builder, mlir::Location loc,
+                        mlir::Type resultType, mlir::Value x);
+
+/// Generate call to Fraction intrinsic runtime routine.
+mlir::Value genFraction(fir::FirOpBuilder &builder, mlir::Location loc,
+                        mlir::Value x);
+
+/// Generate call to Nearest intrinsic runtime routine.
+mlir::Value genNearest(fir::FirOpBuilder &builder, mlir::Location loc,
+                       mlir::Value x, mlir::Value s);
+
+/// Generate call to RRSpacing intrinsic runtime routine.
+mlir::Value genRRSpacing(fir::FirOpBuilder &builder, mlir::Location loc,
+                         mlir::Value x);
+
+/// Generate call to Scale intrinsic runtime routine.
+mlir::Value genScale(fir::FirOpBuilder &builder, mlir::Location loc,
+                     mlir::Value x, mlir::Value i);
+
+/// Generate call to Set_exponent intrinsic runtime routine.
+mlir::Value genSetExponent(fir::FirOpBuilder &builder, mlir::Location loc,
+                           mlir::Value x, mlir::Value i);
+
+/// Generate call to Spacing intrinsic runtime routine.
+mlir::Value genSpacing(fir::FirOpBuilder &builder, mlir::Location loc,
+                       mlir::Value x);
+
+} // namespace fir::runtime
+#endif // FORTRAN_OPTIMIZER_BUILDER_RUNTIME_NUMERIC_H

diff  --git a/flang/lib/Optimizer/Builder/CMakeLists.txt b/flang/lib/Optimizer/Builder/CMakeLists.txt
index 8d95558bcb1c5..4076c77b299bc 100644
--- a/flang/lib/Optimizer/Builder/CMakeLists.txt
+++ b/flang/lib/Optimizer/Builder/CMakeLists.txt
@@ -8,6 +8,7 @@ add_flang_library(FIRBuilder
   FIRBuilder.cpp
   MutableBox.cpp
   Runtime/Assign.cpp
+  Runtime/Numeric.cpp
   Runtime/Reduction.cpp
   Runtime/Transformational.cpp
 

diff  --git a/flang/lib/Optimizer/Builder/Runtime/Numeric.cpp b/flang/lib/Optimizer/Builder/Runtime/Numeric.cpp
new file mode 100644
index 0000000000000..edcb40a7f0a38
--- /dev/null
+++ b/flang/lib/Optimizer/Builder/Runtime/Numeric.cpp
@@ -0,0 +1,398 @@
+//===-- Numeric.cpp -- runtime API for numeric intrinsics -----------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "flang/Optimizer/Builder/Runtime/Numeric.h"
+#include "flang/Optimizer/Builder/BoxValue.h"
+#include "flang/Optimizer/Builder/Character.h"
+#include "flang/Optimizer/Builder/FIRBuilder.h"
+#include "flang/Optimizer/Builder/Runtime/RTBuilder.h"
+#include "flang/Runtime/numeric.h"
+#include "mlir/Dialect/StandardOps/IR/Ops.h"
+
+using namespace Fortran::runtime;
+
+// The real*10 and real*16 placeholders below are used to force the
+// compilation of the real*10 and real*16 method names on systems that
+// may not have them in their runtime library. This can occur in the
+// case of cross compilation, for example.
+
+/// Placeholder for real*10 version of Exponent Intrinsic
+struct ForcedExponent10_4 {
+  static constexpr const char *name = ExpandAndQuoteKey(RTNAME(Exponent10_4));
+  static constexpr fir::runtime::FuncTypeBuilderFunc getTypeModel() {
+    return [](mlir::MLIRContext *ctx) {
+      auto fltTy = mlir::FloatType::getF80(ctx);
+      auto intTy = mlir::IntegerType::get(ctx, 32);
+      return mlir::FunctionType::get(ctx, fltTy, intTy);
+    };
+  }
+};
+
+struct ForcedExponent10_8 {
+  static constexpr const char *name = ExpandAndQuoteKey(RTNAME(Exponent10_8));
+  static constexpr fir::runtime::FuncTypeBuilderFunc getTypeModel() {
+    return [](mlir::MLIRContext *ctx) {
+      auto fltTy = mlir::FloatType::getF80(ctx);
+      auto intTy = mlir::IntegerType::get(ctx, 64);
+      return mlir::FunctionType::get(ctx, fltTy, intTy);
+    };
+  }
+};
+
+/// Placeholder for real*16 version of Exponent Intrinsic
+struct ForcedExponent16_4 {
+  static constexpr const char *name = ExpandAndQuoteKey(RTNAME(Exponent16_4));
+  static constexpr fir::runtime::FuncTypeBuilderFunc getTypeModel() {
+    return [](mlir::MLIRContext *ctx) {
+      auto fltTy = mlir::FloatType::getF128(ctx);
+      auto intTy = mlir::IntegerType::get(ctx, 32);
+      return mlir::FunctionType::get(ctx, fltTy, intTy);
+    };
+  }
+};
+
+struct ForcedExponent16_8 {
+  static constexpr const char *name = ExpandAndQuoteKey(RTNAME(Exponent16_8));
+  static constexpr fir::runtime::FuncTypeBuilderFunc getTypeModel() {
+    return [](mlir::MLIRContext *ctx) {
+      auto fltTy = mlir::FloatType::getF128(ctx);
+      auto intTy = mlir::IntegerType::get(ctx, 64);
+      return mlir::FunctionType::get(ctx, fltTy, intTy);
+    };
+  }
+};
+
+/// Placeholder for real*10 version of Fraction Intrinsic
+struct ForcedFraction10 {
+  static constexpr const char *name = ExpandAndQuoteKey(RTNAME(Fraction10));
+  static constexpr fir::runtime::FuncTypeBuilderFunc getTypeModel() {
+    return [](mlir::MLIRContext *ctx) {
+      auto ty = mlir::FloatType::getF80(ctx);
+      return mlir::FunctionType::get(ctx, {ty}, {ty});
+    };
+  }
+};
+
+/// Placeholder for real*16 version of Fraction Intrinsic
+struct ForcedFraction16 {
+  static constexpr const char *name = ExpandAndQuoteKey(RTNAME(Fraction16));
+  static constexpr fir::runtime::FuncTypeBuilderFunc getTypeModel() {
+    return [](mlir::MLIRContext *ctx) {
+      auto ty = mlir::FloatType::getF128(ctx);
+      return mlir::FunctionType::get(ctx, {ty}, {ty});
+    };
+  }
+};
+
+/// Placeholder for real*10 version of Nearest Intrinsic
+struct ForcedNearest10 {
+  static constexpr const char *name = ExpandAndQuoteKey(RTNAME(Nearest10));
+  static constexpr fir::runtime::FuncTypeBuilderFunc getTypeModel() {
+    return [](mlir::MLIRContext *ctx) {
+      auto fltTy = mlir::FloatType::getF80(ctx);
+      auto boolTy = mlir::IntegerType::get(ctx, 1);
+      return mlir::FunctionType::get(ctx, {fltTy, boolTy}, {fltTy});
+    };
+  }
+};
+
+/// Placeholder for real*16 version of Nearest Intrinsic
+struct ForcedNearest16 {
+  static constexpr const char *name = ExpandAndQuoteKey(RTNAME(Nearest16));
+  static constexpr fir::runtime::FuncTypeBuilderFunc getTypeModel() {
+    return [](mlir::MLIRContext *ctx) {
+      auto fltTy = mlir::FloatType::getF128(ctx);
+      auto boolTy = mlir::IntegerType::get(ctx, 1);
+      return mlir::FunctionType::get(ctx, {fltTy, boolTy}, {fltTy});
+    };
+  }
+};
+
+/// Placeholder for real*10 version of RRSpacing Intrinsic
+struct ForcedRRSpacing10 {
+  static constexpr const char *name = ExpandAndQuoteKey(RTNAME(RRSpacing10));
+  static constexpr fir::runtime::FuncTypeBuilderFunc getTypeModel() {
+    return [](mlir::MLIRContext *ctx) {
+      auto ty = mlir::FloatType::getF80(ctx);
+      return mlir::FunctionType::get(ctx, {ty}, {ty});
+    };
+  }
+};
+
+/// Placeholder for real*16 version of RRSpacing Intrinsic
+struct ForcedRRSpacing16 {
+  static constexpr const char *name = ExpandAndQuoteKey(RTNAME(RRSpacing16));
+  static constexpr fir::runtime::FuncTypeBuilderFunc getTypeModel() {
+    return [](mlir::MLIRContext *ctx) {
+      auto ty = mlir::FloatType::getF128(ctx);
+      return mlir::FunctionType::get(ctx, {ty}, {ty});
+    };
+  }
+};
+
+/// Placeholder for real*10 version of Scale Intrinsic
+struct ForcedScale10 {
+  static constexpr const char *name = ExpandAndQuoteKey(RTNAME(Scale10));
+  static constexpr fir::runtime::FuncTypeBuilderFunc getTypeModel() {
+    return [](mlir::MLIRContext *ctx) {
+      auto fltTy = mlir::FloatType::getF80(ctx);
+      auto intTy = mlir::IntegerType::get(ctx, 64);
+      return mlir::FunctionType::get(ctx, {fltTy, intTy}, {fltTy});
+    };
+  }
+};
+
+/// Placeholder for real*16 version of Scale Intrinsic
+struct ForcedScale16 {
+  static constexpr const char *name = ExpandAndQuoteKey(RTNAME(Scale16));
+  static constexpr fir::runtime::FuncTypeBuilderFunc getTypeModel() {
+    return [](mlir::MLIRContext *ctx) {
+      auto fltTy = mlir::FloatType::getF128(ctx);
+      auto intTy = mlir::IntegerType::get(ctx, 64);
+      return mlir::FunctionType::get(ctx, {fltTy, intTy}, {fltTy});
+    };
+  }
+};
+
+/// Placeholder for real*10 version of RRSpacing Intrinsic
+struct ForcedSetExponent10 {
+  static constexpr const char *name = ExpandAndQuoteKey(RTNAME(SetExponent10));
+  static constexpr fir::runtime::FuncTypeBuilderFunc getTypeModel() {
+    return [](mlir::MLIRContext *ctx) {
+      auto fltTy = mlir::FloatType::getF80(ctx);
+      auto intTy = mlir::IntegerType::get(ctx, 64);
+      return mlir::FunctionType::get(ctx, {fltTy, intTy}, {fltTy});
+    };
+  }
+};
+
+/// Placeholder for real*10 version of RRSpacing Intrinsic
+struct ForcedSetExponent16 {
+  static constexpr const char *name = ExpandAndQuoteKey(RTNAME(SetExponent16));
+  static constexpr fir::runtime::FuncTypeBuilderFunc getTypeModel() {
+    return [](mlir::MLIRContext *ctx) {
+      auto fltTy = mlir::FloatType::getF128(ctx);
+      auto intTy = mlir::IntegerType::get(ctx, 64);
+      return mlir::FunctionType::get(ctx, {fltTy, intTy}, {fltTy});
+    };
+  }
+};
+
+/// Placeholder for real*10 version of Spacing Intrinsic
+struct ForcedSpacing10 {
+  static constexpr const char *name = ExpandAndQuoteKey(RTNAME(Spacing10));
+  static constexpr fir::runtime::FuncTypeBuilderFunc getTypeModel() {
+    return [](mlir::MLIRContext *ctx) {
+      auto ty = mlir::FloatType::getF80(ctx);
+      return mlir::FunctionType::get(ctx, {ty}, {ty});
+    };
+  }
+};
+
+/// Placeholder for real*16 version of Spacing Intrinsic
+struct ForcedSpacing16 {
+  static constexpr const char *name = ExpandAndQuoteKey(RTNAME(Spacing16));
+  static constexpr fir::runtime::FuncTypeBuilderFunc getTypeModel() {
+    return [](mlir::MLIRContext *ctx) {
+      auto ty = mlir::FloatType::getF128(ctx);
+      return mlir::FunctionType::get(ctx, {ty}, {ty});
+    };
+  }
+};
+
+/// Generate call to Exponent instrinsic runtime routine.
+mlir::Value fir::runtime::genExponent(fir::FirOpBuilder &builder,
+                                      mlir::Location loc, mlir::Type resultType,
+                                      mlir::Value x) {
+  mlir::FuncOp func;
+  mlir::Type fltTy = x.getType();
+
+  if (fltTy.isF32()) {
+    if (resultType.isInteger(32))
+      func = fir::runtime::getRuntimeFunc<mkRTKey(Exponent4_4)>(loc, builder);
+    else if (resultType.isInteger(64))
+      func = fir::runtime::getRuntimeFunc<mkRTKey(Exponent4_8)>(loc, builder);
+  } else if (fltTy.isF64()) {
+    if (resultType.isInteger(32))
+      func = fir::runtime::getRuntimeFunc<mkRTKey(Exponent8_4)>(loc, builder);
+    else if (resultType.isInteger(64))
+      func = fir::runtime::getRuntimeFunc<mkRTKey(Exponent8_8)>(loc, builder);
+  } else if (fltTy.isF80()) {
+    if (resultType.isInteger(32))
+      func = fir::runtime::getRuntimeFunc<ForcedExponent10_4>(loc, builder);
+    else if (resultType.isInteger(64))
+      func = fir::runtime::getRuntimeFunc<ForcedExponent10_8>(loc, builder);
+  } else if (fltTy.isF128()) {
+    if (resultType.isInteger(32))
+      func = fir::runtime::getRuntimeFunc<ForcedExponent16_4>(loc, builder);
+    else if (resultType.isInteger(64))
+      func = fir::runtime::getRuntimeFunc<ForcedExponent16_8>(loc, builder);
+  } else
+    fir::emitFatalError(loc, "unsupported real kind in Exponent lowering");
+
+  auto funcTy = func.getType();
+  llvm::SmallVector<mlir::Value> args = {
+      builder.createConvert(loc, funcTy.getInput(0), x)};
+
+  return builder.create<fir::CallOp>(loc, func, args).getResult(0);
+}
+
+/// Generate call to Fraction instrinsic runtime routine.
+mlir::Value fir::runtime::genFraction(fir::FirOpBuilder &builder,
+                                      mlir::Location loc, mlir::Value x) {
+  mlir::FuncOp func;
+  mlir::Type fltTy = x.getType();
+
+  if (fltTy.isF32())
+    func = fir::runtime::getRuntimeFunc<mkRTKey(Fraction4)>(loc, builder);
+  else if (fltTy.isF64())
+    func = fir::runtime::getRuntimeFunc<mkRTKey(Fraction8)>(loc, builder);
+  else if (fltTy.isF80())
+    func = fir::runtime::getRuntimeFunc<ForcedFraction10>(loc, builder);
+  else if (fltTy.isF128())
+    func = fir::runtime::getRuntimeFunc<ForcedFraction16>(loc, builder);
+  else
+    fir::emitFatalError(loc, "unsupported real kind in Fraction lowering");
+
+  auto funcTy = func.getType();
+  llvm::SmallVector<mlir::Value> args = {
+      builder.createConvert(loc, funcTy.getInput(0), x)};
+
+  return builder.create<fir::CallOp>(loc, func, args).getResult(0);
+}
+
+/// Generate call to Nearest intrinsic runtime routine.
+mlir::Value fir::runtime::genNearest(fir::FirOpBuilder &builder,
+                                     mlir::Location loc, mlir::Value x,
+                                     mlir::Value s) {
+  mlir::FuncOp func;
+  mlir::Type fltTy = x.getType();
+
+  if (fltTy.isF32())
+    func = fir::runtime::getRuntimeFunc<mkRTKey(Nearest4)>(loc, builder);
+  else if (fltTy.isF64())
+    func = fir::runtime::getRuntimeFunc<mkRTKey(Nearest8)>(loc, builder);
+  else if (fltTy.isF80())
+    func = fir::runtime::getRuntimeFunc<ForcedNearest10>(loc, builder);
+  else if (fltTy.isF128())
+    func = fir::runtime::getRuntimeFunc<ForcedNearest16>(loc, builder);
+  else
+    fir::emitFatalError(loc, "unsupported REAL kind in Nearest lowering");
+
+  auto funcTy = func.getType();
+
+  mlir::Type sTy = s.getType();
+  mlir::Value zero = builder.createRealZeroConstant(loc, sTy);
+  auto cmp = builder.create<mlir::arith::CmpFOp>(
+      loc, mlir::arith::CmpFPredicate::OGT, s, zero);
+
+  mlir::Type boolTy = mlir::IntegerType::get(builder.getContext(), 1);
+  mlir::Value False = builder.createIntegerConstant(loc, boolTy, 0);
+  mlir::Value True = builder.createIntegerConstant(loc, boolTy, 1);
+
+  mlir::Value positive = builder.create<mlir::SelectOp>(loc, cmp, True, False);
+  auto args = fir::runtime::createArguments(builder, loc, funcTy, x, positive);
+
+  return builder.create<fir::CallOp>(loc, func, args).getResult(0);
+}
+
+/// Generate call to RRSpacing intrinsic runtime routine.
+mlir::Value fir::runtime::genRRSpacing(fir::FirOpBuilder &builder,
+                                       mlir::Location loc, mlir::Value x) {
+  mlir::FuncOp func;
+  mlir::Type fltTy = x.getType();
+
+  if (fltTy.isF32())
+    func = fir::runtime::getRuntimeFunc<mkRTKey(RRSpacing4)>(loc, builder);
+  else if (fltTy.isF64())
+    func = fir::runtime::getRuntimeFunc<mkRTKey(RRSpacing8)>(loc, builder);
+  else if (fltTy.isF80())
+    func = fir::runtime::getRuntimeFunc<ForcedRRSpacing10>(loc, builder);
+  else if (fltTy.isF128())
+    func = fir::runtime::getRuntimeFunc<ForcedRRSpacing16>(loc, builder);
+  else
+    fir::emitFatalError(loc, "unsupported real kind in RRSpacing lowering");
+
+  auto funcTy = func.getType();
+  llvm::SmallVector<mlir::Value> args = {
+      builder.createConvert(loc, funcTy.getInput(0), x)};
+
+  return builder.create<fir::CallOp>(loc, func, args).getResult(0);
+}
+
+/// Generate call to Scale intrinsic runtime routine.
+mlir::Value fir::runtime::genScale(fir::FirOpBuilder &builder,
+                                   mlir::Location loc, mlir::Value x,
+                                   mlir::Value i) {
+  mlir::FuncOp func;
+  mlir::Type fltTy = x.getType();
+
+  if (fltTy.isF32())
+    func = fir::runtime::getRuntimeFunc<mkRTKey(Scale4)>(loc, builder);
+  else if (fltTy.isF64())
+    func = fir::runtime::getRuntimeFunc<mkRTKey(Scale8)>(loc, builder);
+  else if (fltTy.isF80())
+    func = fir::runtime::getRuntimeFunc<ForcedScale10>(loc, builder);
+  else if (fltTy.isF128())
+    func = fir::runtime::getRuntimeFunc<ForcedScale16>(loc, builder);
+  else
+    fir::emitFatalError(loc, "unsupported REAL kind in Scale lowering");
+
+  auto funcTy = func.getType();
+  auto args = fir::runtime::createArguments(builder, loc, funcTy, x, i);
+
+  return builder.create<fir::CallOp>(loc, func, args).getResult(0);
+}
+
+/// Generate call to Set_exponent instrinsic runtime routine.
+mlir::Value fir::runtime::genSetExponent(fir::FirOpBuilder &builder,
+                                         mlir::Location loc, mlir::Value x,
+                                         mlir::Value i) {
+  mlir::FuncOp func;
+  mlir::Type fltTy = x.getType();
+
+  if (fltTy.isF32())
+    func = fir::runtime::getRuntimeFunc<mkRTKey(SetExponent4)>(loc, builder);
+  else if (fltTy.isF64())
+    func = fir::runtime::getRuntimeFunc<mkRTKey(SetExponent8)>(loc, builder);
+  else if (fltTy.isF80())
+    func = fir::runtime::getRuntimeFunc<ForcedSetExponent10>(loc, builder);
+  else if (fltTy.isF128())
+    func = fir::runtime::getRuntimeFunc<ForcedSetExponent16>(loc, builder);
+  else
+    fir::emitFatalError(loc, "unsupported real kind in Fraction lowering");
+
+  auto funcTy = func.getType();
+  auto args = fir::runtime::createArguments(builder, loc, funcTy, x, i);
+
+  return builder.create<fir::CallOp>(loc, func, args).getResult(0);
+}
+
+/// Generate call to Spacing intrinsic runtime routine.
+mlir::Value fir::runtime::genSpacing(fir::FirOpBuilder &builder,
+                                     mlir::Location loc, mlir::Value x) {
+  mlir::FuncOp func;
+  mlir::Type fltTy = x.getType();
+
+  if (fltTy.isF32())
+    func = fir::runtime::getRuntimeFunc<mkRTKey(Spacing4)>(loc, builder);
+  else if (fltTy.isF64())
+    func = fir::runtime::getRuntimeFunc<mkRTKey(Spacing8)>(loc, builder);
+  else if (fltTy.isF80())
+    func = fir::runtime::getRuntimeFunc<ForcedSpacing10>(loc, builder);
+  else if (fltTy.isF128())
+    func = fir::runtime::getRuntimeFunc<ForcedSpacing16>(loc, builder);
+  else
+    fir::emitFatalError(loc, "unsupported real kind in Spacing lowering");
+
+  auto funcTy = func.getType();
+  llvm::SmallVector<mlir::Value> args = {
+      builder.createConvert(loc, funcTy.getInput(0), x)};
+
+  return builder.create<fir::CallOp>(loc, func, args).getResult(0);
+}

diff  --git a/flang/unittests/Optimizer/Builder/Runtime/NumericTest.cpp b/flang/unittests/Optimizer/Builder/Runtime/NumericTest.cpp
new file mode 100644
index 0000000000000..13dd80ef378f6
--- /dev/null
+++ b/flang/unittests/Optimizer/Builder/Runtime/NumericTest.cpp
@@ -0,0 +1,123 @@
+//===- NumericTest.cpp -- Numeric intrinsic runtime builder unit tests ----===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "flang/Optimizer/Builder/Runtime/Numeric.h"
+#include "RuntimeCallTestBase.h"
+#include "gtest/gtest.h"
+
+void testGenExponent(fir::FirOpBuilder &builder, mlir::Type resultType,
+    mlir::Type xType, llvm::StringRef fctName) {
+  auto loc = builder.getUnknownLoc();
+  mlir::Value x = builder.create<fir::UndefOp>(loc, xType);
+  mlir::Value exp = fir::runtime::genExponent(builder, loc, resultType, x);
+  checkCallOp(exp.getDefiningOp(), fctName, 1, /*addLocArg=*/false);
+}
+
+TEST_F(RuntimeCallTest, genExponentTest) {
+  testGenExponent(*firBuilder, i32Ty, f32Ty, "_FortranAExponent4_4");
+  testGenExponent(*firBuilder, i64Ty, f32Ty, "_FortranAExponent4_8");
+  testGenExponent(*firBuilder, i32Ty, f64Ty, "_FortranAExponent8_4");
+  testGenExponent(*firBuilder, i64Ty, f64Ty, "_FortranAExponent8_8");
+  testGenExponent(*firBuilder, i32Ty, f80Ty, "_FortranAExponent10_4");
+  testGenExponent(*firBuilder, i64Ty, f80Ty, "_FortranAExponent10_8");
+  testGenExponent(*firBuilder, i32Ty, f128Ty, "_FortranAExponent16_4");
+  testGenExponent(*firBuilder, i64Ty, f128Ty, "_FortranAExponent16_8");
+}
+
+void testGenX(fir::FirOpBuilder &builder, mlir::Type xType,
+    mlir::Value (*genFct)(fir::FirOpBuilder &, Location, mlir::Value),
+    llvm::StringRef fctName) {
+  auto loc = builder.getUnknownLoc();
+  mlir::Value x = builder.create<fir::UndefOp>(loc, xType);
+  mlir::Value val = genFct(builder, loc, x);
+  checkCallOp(val.getDefiningOp(), fctName, 1, /*addLocArg=*/false);
+}
+
+TEST_F(RuntimeCallTest, genFractionTest) {
+  testGenX(*firBuilder, f32Ty, fir::runtime::genFraction, "_FortranAFraction4");
+  testGenX(*firBuilder, f64Ty, fir::runtime::genFraction, "_FortranAFraction8");
+  testGenX(
+      *firBuilder, f80Ty, fir::runtime::genFraction, "_FortranAFraction10");
+  testGenX(
+      *firBuilder, f128Ty, fir::runtime::genFraction, "_FortranAFraction16");
+}
+
+void testGenNearest(fir::FirOpBuilder &builder, mlir::Type xType,
+    mlir::Type sType, llvm::StringRef fctName) {
+  auto loc = builder.getUnknownLoc();
+  mlir::Value x = builder.create<fir::UndefOp>(loc, xType);
+  mlir::Value s = builder.create<fir::UndefOp>(loc, sType);
+  mlir::Value nearest = fir::runtime::genNearest(builder, loc, x, s);
+  checkCallOp(nearest.getDefiningOp(), fctName, 2, /*addLocArg=*/false);
+  auto callOp = mlir::dyn_cast<fir::CallOp>(nearest.getDefiningOp());
+  mlir::Value select = callOp.getOperands()[1];
+  EXPECT_TRUE(mlir::isa<mlir::SelectOp>(select.getDefiningOp()));
+  auto selectOp = mlir::dyn_cast<mlir::SelectOp>(select.getDefiningOp());
+  mlir::Value cmp = selectOp.condition();
+  EXPECT_TRUE(mlir::isa<mlir::arith::CmpFOp>(cmp.getDefiningOp()));
+  auto cmpOp = mlir::dyn_cast<mlir::arith::CmpFOp>(cmp.getDefiningOp());
+  EXPECT_EQ(s, cmpOp.lhs());
+}
+
+TEST_F(RuntimeCallTest, genNearestTest) {
+  testGenNearest(*firBuilder, f32Ty, f32Ty, "_FortranANearest4");
+  testGenNearest(*firBuilder, f64Ty, f32Ty, "_FortranANearest8");
+  testGenNearest(*firBuilder, f80Ty, f32Ty, "_FortranANearest10");
+  testGenNearest(*firBuilder, f128Ty, f32Ty, "_FortranANearest16");
+}
+
+TEST_F(RuntimeCallTest, genRRSpacingTest) {
+  testGenX(
+      *firBuilder, f32Ty, fir::runtime::genRRSpacing, "_FortranARRSpacing4");
+  testGenX(
+      *firBuilder, f64Ty, fir::runtime::genRRSpacing, "_FortranARRSpacing8");
+  testGenX(
+      *firBuilder, f80Ty, fir::runtime::genRRSpacing, "_FortranARRSpacing10");
+  testGenX(
+      *firBuilder, f128Ty, fir::runtime::genRRSpacing, "_FortranARRSpacing16");
+}
+
+void testGenXI(fir::FirOpBuilder &builder, mlir::Type xType, mlir::Type iType,
+    mlir::Value (*genFct)(
+        fir::FirOpBuilder &, Location, mlir::Value, mlir::Value),
+    llvm::StringRef fctName) {
+  auto loc = builder.getUnknownLoc();
+  mlir::Value x = builder.create<fir::UndefOp>(loc, xType);
+  mlir::Value i = builder.create<fir::UndefOp>(loc, iType);
+  mlir::Value val = genFct(builder, loc, x, i);
+  checkCallOp(val.getDefiningOp(), fctName, 2, /*addLocArg=*/false);
+}
+
+TEST_F(RuntimeCallTest, genScaleTest) {
+  testGenXI(
+      *firBuilder, f32Ty, f32Ty, fir::runtime::genScale, "_FortranAScale4");
+  testGenXI(
+      *firBuilder, f64Ty, f32Ty, fir::runtime::genScale, "_FortranAScale8");
+  testGenXI(
+      *firBuilder, f80Ty, f32Ty, fir::runtime::genScale, "_FortranAScale10");
+  testGenXI(
+      *firBuilder, f128Ty, f32Ty, fir::runtime::genScale, "_FortranAScale16");
+}
+
+TEST_F(RuntimeCallTest, genSetExponentTest) {
+  testGenXI(*firBuilder, f32Ty, f32Ty, fir::runtime::genSetExponent,
+      "_FortranASetExponent4");
+  testGenXI(*firBuilder, f64Ty, f32Ty, fir::runtime::genSetExponent,
+      "_FortranASetExponent8");
+  testGenXI(*firBuilder, f80Ty, f32Ty, fir::runtime::genSetExponent,
+      "_FortranASetExponent10");
+  testGenXI(*firBuilder, f128Ty, f32Ty, fir::runtime::genSetExponent,
+      "_FortranASetExponent16");
+}
+
+TEST_F(RuntimeCallTest, genSpacingTest) {
+  testGenX(*firBuilder, f32Ty, fir::runtime::genSpacing, "_FortranASpacing4");
+  testGenX(*firBuilder, f64Ty, fir::runtime::genSpacing, "_FortranASpacing8");
+  testGenX(*firBuilder, f80Ty, fir::runtime::genSpacing, "_FortranASpacing10");
+  testGenX(*firBuilder, f128Ty, fir::runtime::genSpacing, "_FortranASpacing16");
+}

diff  --git a/flang/unittests/Optimizer/CMakeLists.txt b/flang/unittests/Optimizer/CMakeLists.txt
index 1ade44cd1904f..2f0f9c99fe3dc 100644
--- a/flang/unittests/Optimizer/CMakeLists.txt
+++ b/flang/unittests/Optimizer/CMakeLists.txt
@@ -14,6 +14,7 @@ add_flang_unittest(FlangOptimizerTests
   Builder/DoLoopHelperTest.cpp
   Builder/FIRBuilderTest.cpp
   Builder/Runtime/AssignTest.cpp
+  Builder/Runtime/NumericTest.cpp
   Builder/Runtime/ReductionTest.cpp
   Builder/Runtime/TransformationalTest.cpp
   FIRContextTest.cpp


        


More information about the flang-commits mailing list