510 lines
20 KiB
C++
510 lines
20 KiB
C++
|
//===-- 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/Optimizer/Support/Utils.h"
|
||
|
#include "flang/Runtime/numeric.h"
|
||
|
#include "mlir/Dialect/Func/IR/FuncOps.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 Mod Intrinsic
|
||
|
struct ForcedMod10 {
|
||
|
static constexpr const char *name = ExpandAndQuoteKey(RTNAME(ModReal10));
|
||
|
static constexpr fir::runtime::FuncTypeBuilderFunc getTypeModel() {
|
||
|
return [](mlir::MLIRContext *ctx) {
|
||
|
auto fltTy = mlir::FloatType::getF80(ctx);
|
||
|
auto strTy = fir::ReferenceType::get(mlir::IntegerType::get(ctx, 8));
|
||
|
auto intTy = mlir::IntegerType::get(ctx, 8 * sizeof(int));
|
||
|
return mlir::FunctionType::get(ctx, {fltTy, fltTy, strTy, intTy},
|
||
|
{fltTy});
|
||
|
};
|
||
|
}
|
||
|
};
|
||
|
|
||
|
/// Placeholder for real*16 version of Mod Intrinsic
|
||
|
struct ForcedMod16 {
|
||
|
static constexpr const char *name = ExpandAndQuoteKey(RTNAME(ModReal16));
|
||
|
static constexpr fir::runtime::FuncTypeBuilderFunc getTypeModel() {
|
||
|
return [](mlir::MLIRContext *ctx) {
|
||
|
auto fltTy = mlir::FloatType::getF128(ctx);
|
||
|
auto strTy = fir::ReferenceType::get(mlir::IntegerType::get(ctx, 8));
|
||
|
auto intTy = mlir::IntegerType::get(ctx, 8 * sizeof(int));
|
||
|
return mlir::FunctionType::get(ctx, {fltTy, fltTy, strTy, intTy},
|
||
|
{fltTy});
|
||
|
};
|
||
|
}
|
||
|
};
|
||
|
|
||
|
/// 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::func::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::intrinsicTypeTODO(builder, fltTy, loc, "EXPONENT");
|
||
|
|
||
|
auto funcTy = func.getFunctionType();
|
||
|
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::func::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::intrinsicTypeTODO(builder, fltTy, loc, "FRACTION");
|
||
|
|
||
|
auto funcTy = func.getFunctionType();
|
||
|
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 Mod intrinsic runtime routine.
|
||
|
mlir::Value fir::runtime::genMod(fir::FirOpBuilder &builder, mlir::Location loc,
|
||
|
mlir::Value a, mlir::Value p) {
|
||
|
mlir::func::FuncOp func;
|
||
|
mlir::Type fltTy = a.getType();
|
||
|
|
||
|
if (fltTy != p.getType())
|
||
|
fir::emitFatalError(loc, "arguments type mismatch in MOD");
|
||
|
|
||
|
if (fltTy.isF32())
|
||
|
func = fir::runtime::getRuntimeFunc<mkRTKey(ModReal4)>(loc, builder);
|
||
|
else if (fltTy.isF64())
|
||
|
func = fir::runtime::getRuntimeFunc<mkRTKey(ModReal8)>(loc, builder);
|
||
|
else if (fltTy.isF80())
|
||
|
func = fir::runtime::getRuntimeFunc<ForcedMod10>(loc, builder);
|
||
|
else if (fltTy.isF128())
|
||
|
func = fir::runtime::getRuntimeFunc<ForcedMod16>(loc, builder);
|
||
|
else
|
||
|
fir::intrinsicTypeTODO(builder, fltTy, loc, "MOD");
|
||
|
|
||
|
auto funcTy = func.getFunctionType();
|
||
|
auto sourceFile = fir::factory::locationToFilename(builder, loc);
|
||
|
auto sourceLine =
|
||
|
fir::factory::locationToLineNo(builder, loc, funcTy.getInput(3));
|
||
|
auto args = fir::runtime::createArguments(builder, loc, funcTy, a, p,
|
||
|
sourceFile, sourceLine);
|
||
|
|
||
|
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::func::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::intrinsicTypeTODO(builder, fltTy, loc, "NEAREST");
|
||
|
|
||
|
auto funcTy = func.getFunctionType();
|
||
|
|
||
|
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::arith::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::func::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::intrinsicTypeTODO(builder, fltTy, loc, "RRSPACING");
|
||
|
|
||
|
auto funcTy = func.getFunctionType();
|
||
|
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::func::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::intrinsicTypeTODO(builder, fltTy, loc, "SCALE");
|
||
|
|
||
|
auto funcTy = func.getFunctionType();
|
||
|
auto args = fir::runtime::createArguments(builder, loc, funcTy, x, i);
|
||
|
|
||
|
return builder.create<fir::CallOp>(loc, func, args).getResult(0);
|
||
|
}
|
||
|
|
||
|
/// Generate call to Selected_int_kind intrinsic runtime routine.
|
||
|
mlir::Value fir::runtime::genSelectedIntKind(fir::FirOpBuilder &builder,
|
||
|
mlir::Location loc,
|
||
|
mlir::Value x) {
|
||
|
mlir::func::FuncOp func =
|
||
|
fir::runtime::getRuntimeFunc<mkRTKey(SelectedIntKind)>(loc, builder);
|
||
|
auto fTy = func.getFunctionType();
|
||
|
auto sourceFile = fir::factory::locationToFilename(builder, loc);
|
||
|
auto sourceLine =
|
||
|
fir::factory::locationToLineNo(builder, loc, fTy.getInput(1));
|
||
|
if (!fir::isa_ref_type(x.getType()))
|
||
|
fir::emitFatalError(loc, "argument address for runtime not found");
|
||
|
mlir::Type eleTy = fir::unwrapRefType(x.getType());
|
||
|
mlir::Value xKind = builder.createIntegerConstant(
|
||
|
loc, fTy.getInput(3), eleTy.getIntOrFloatBitWidth() / 8);
|
||
|
auto args = fir::runtime::createArguments(builder, loc, fTy, sourceFile,
|
||
|
sourceLine, x, xKind);
|
||
|
|
||
|
return builder.create<fir::CallOp>(loc, func, args).getResult(0);
|
||
|
}
|
||
|
|
||
|
/// Generate call to Selected_real_kind intrinsic runtime routine.
|
||
|
mlir::Value fir::runtime::genSelectedRealKind(fir::FirOpBuilder &builder,
|
||
|
mlir::Location loc,
|
||
|
mlir::Value precision,
|
||
|
mlir::Value range,
|
||
|
mlir::Value radix) {
|
||
|
mlir::func::FuncOp func =
|
||
|
fir::runtime::getRuntimeFunc<mkRTKey(SelectedRealKind)>(loc, builder);
|
||
|
auto fTy = func.getFunctionType();
|
||
|
auto getArgKinds = [&](mlir::Value arg, int argKindIndex) -> mlir::Value {
|
||
|
if (fir::isa_ref_type(arg.getType())) {
|
||
|
mlir::Type eleTy = fir::unwrapRefType(arg.getType());
|
||
|
return builder.createIntegerConstant(loc, fTy.getInput(argKindIndex),
|
||
|
eleTy.getIntOrFloatBitWidth() / 8);
|
||
|
} else {
|
||
|
return builder.createIntegerConstant(loc, fTy.getInput(argKindIndex), 0);
|
||
|
}
|
||
|
};
|
||
|
|
||
|
auto sourceFile = fir::factory::locationToFilename(builder, loc);
|
||
|
auto sourceLine =
|
||
|
fir::factory::locationToLineNo(builder, loc, fTy.getInput(1));
|
||
|
mlir::Value pKind = getArgKinds(precision, 3);
|
||
|
mlir::Value rKind = getArgKinds(range, 5);
|
||
|
mlir::Value dKind = getArgKinds(radix, 7);
|
||
|
auto args = fir::runtime::createArguments(builder, loc, fTy, sourceFile,
|
||
|
sourceLine, precision, pKind, range,
|
||
|
rKind, radix, dKind);
|
||
|
|
||
|
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::func::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::intrinsicTypeTODO(builder, fltTy, loc, "SET_EXPONENT");
|
||
|
|
||
|
auto funcTy = func.getFunctionType();
|
||
|
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::func::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::intrinsicTypeTODO(builder, fltTy, loc, "SPACING");
|
||
|
|
||
|
auto funcTy = func.getFunctionType();
|
||
|
llvm::SmallVector<mlir::Value> args = {
|
||
|
builder.createConvert(loc, funcTy.getInput(0), x)};
|
||
|
|
||
|
return builder.create<fir::CallOp>(loc, func, args).getResult(0);
|
||
|
}
|