diff --git a/flang/include/flang/Optimizer/Builder/Runtime/Numeric.h b/flang/include/flang/Optimizer/Builder/Runtime/Numeric.h new file mode 100644 --- /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 --- a/flang/lib/Optimizer/Builder/CMakeLists.txt +++ b/flang/lib/Optimizer/Builder/CMakeLists.txt @@ -7,6 +7,7 @@ DoLoopHelper.cpp FIRBuilder.cpp MutableBox.cpp + Runtime/Numeric.cpp DEPENDS FIRDialect diff --git a/flang/lib/Optimizer/Builder/Runtime/Numeric.cpp b/flang/lib/Optimizer/Builder/Runtime/Numeric.cpp new file mode 100644 --- /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(loc, builder); + else if (resultType.isInteger(64)) + func = fir::runtime::getRuntimeFunc(loc, builder); + } else if (fltTy.isF64()) { + if (resultType.isInteger(32)) + func = fir::runtime::getRuntimeFunc(loc, builder); + else if (resultType.isInteger(64)) + func = fir::runtime::getRuntimeFunc(loc, builder); + } else if (fltTy.isF80()) { + if (resultType.isInteger(32)) + func = fir::runtime::getRuntimeFunc(loc, builder); + else if (resultType.isInteger(64)) + func = fir::runtime::getRuntimeFunc(loc, builder); + } else if (fltTy.isF128()) { + if (resultType.isInteger(32)) + func = fir::runtime::getRuntimeFunc(loc, builder); + else if (resultType.isInteger(64)) + func = fir::runtime::getRuntimeFunc(loc, builder); + } else + fir::emitFatalError(loc, "unsupported real kind in Exponent lowering"); + + auto funcTy = func.getType(); + llvm::SmallVector args = { + builder.createConvert(loc, funcTy.getInput(0), x)}; + + return builder.create(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(loc, builder); + else if (fltTy.isF64()) + func = fir::runtime::getRuntimeFunc(loc, builder); + else if (fltTy.isF80()) + func = fir::runtime::getRuntimeFunc(loc, builder); + else if (fltTy.isF128()) + func = fir::runtime::getRuntimeFunc(loc, builder); + else + fir::emitFatalError(loc, "unsupported real kind in Fraction lowering"); + + auto funcTy = func.getType(); + llvm::SmallVector args = { + builder.createConvert(loc, funcTy.getInput(0), x)}; + + return builder.create(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(loc, builder); + else if (fltTy.isF64()) + func = fir::runtime::getRuntimeFunc(loc, builder); + else if (fltTy.isF80()) + func = fir::runtime::getRuntimeFunc(loc, builder); + else if (fltTy.isF128()) + func = fir::runtime::getRuntimeFunc(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( + 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(loc, cmp, True, False); + auto args = fir::runtime::createArguments(builder, loc, funcTy, x, positive); + + return builder.create(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(loc, builder); + else if (fltTy.isF64()) + func = fir::runtime::getRuntimeFunc(loc, builder); + else if (fltTy.isF80()) + func = fir::runtime::getRuntimeFunc(loc, builder); + else if (fltTy.isF128()) + func = fir::runtime::getRuntimeFunc(loc, builder); + else + fir::emitFatalError(loc, "unsupported real kind in RRSpacing lowering"); + + auto funcTy = func.getType(); + llvm::SmallVector args = { + builder.createConvert(loc, funcTy.getInput(0), x)}; + + return builder.create(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(loc, builder); + else if (fltTy.isF64()) + func = fir::runtime::getRuntimeFunc(loc, builder); + else if (fltTy.isF80()) + func = fir::runtime::getRuntimeFunc(loc, builder); + else if (fltTy.isF128()) + func = fir::runtime::getRuntimeFunc(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(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(loc, builder); + else if (fltTy.isF64()) + func = fir::runtime::getRuntimeFunc(loc, builder); + else if (fltTy.isF80()) + func = fir::runtime::getRuntimeFunc(loc, builder); + else if (fltTy.isF128()) + func = fir::runtime::getRuntimeFunc(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(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(loc, builder); + else if (fltTy.isF64()) + func = fir::runtime::getRuntimeFunc(loc, builder); + else if (fltTy.isF80()) + func = fir::runtime::getRuntimeFunc(loc, builder); + else if (fltTy.isF128()) + func = fir::runtime::getRuntimeFunc(loc, builder); + else + fir::emitFatalError(loc, "unsupported real kind in Spacing lowering"); + + auto funcTy = func.getType(); + llvm::SmallVector args = { + builder.createConvert(loc, funcTy.getInput(0), x)}; + + return builder.create(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 --- /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(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(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(loc, xType); + mlir::Value s = builder.create(loc, sType); + mlir::Value nearest = fir::runtime::genNearest(builder, loc, x, s); + checkCallOp(nearest.getDefiningOp(), fctName, 2, /*addLocArg=*/false); + auto callOp = mlir::dyn_cast(nearest.getDefiningOp()); + mlir::Value select = callOp.getOperands()[1]; + EXPECT_TRUE(mlir::isa(select.getDefiningOp())); + auto selectOp = mlir::dyn_cast(select.getDefiningOp()); + mlir::Value cmp = selectOp.condition(); + EXPECT_TRUE(mlir::isa(cmp.getDefiningOp())); + auto cmpOp = mlir::dyn_cast(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(loc, xType); + mlir::Value i = builder.create(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 --- a/flang/unittests/Optimizer/CMakeLists.txt +++ b/flang/unittests/Optimizer/CMakeLists.txt @@ -13,6 +13,7 @@ Builder/ComplexTest.cpp Builder/DoLoopHelperTest.cpp Builder/FIRBuilderTest.cpp + Builder/Runtime/NumericTest.cpp FIRContextTest.cpp InternalNamesTest.cpp KindMappingTest.cpp