diff --git a/flang/include/flang/Optimizer/Builder/Runtime/RTBuilder.h b/flang/include/flang/Optimizer/Builder/Runtime/RTBuilder.h new file mode 100644 --- /dev/null +++ b/flang/include/flang/Optimizer/Builder/Runtime/RTBuilder.h @@ -0,0 +1,415 @@ +//===-- RTBuilder.h ---------------------------------------------*- 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 +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// This file defines some C++17 template classes that are used to convert the +/// signatures of plain old C functions into a model that can be used to +/// generate MLIR calls to those functions. This can be used to autogenerate +/// tables at compiler compile-time to call runtime support code. +/// +//===----------------------------------------------------------------------===// + +#ifndef FORTRAN_OPTIMIZER_BUILDER_RUNTIME_RTBUILDER_H +#define FORTRAN_OPTIMIZER_BUILDER_RUNTIME_RTBUILDER_H + +#include "flang/Common/Fortran.h" +#include "flang/Common/uint128.h" +#include "flang/Optimizer/Builder/FIRBuilder.h" +#include "flang/Optimizer/Dialect/FIRType.h" +#include "mlir/IR/BuiltinTypes.h" +#include "mlir/IR/MLIRContext.h" +#include "llvm/ADT/SmallVector.h" +#include + +// Incomplete type indicating C99 complex ABI in interfaces. Beware, _Complex +// and std::complex are layout compatible, but not compatible in all ABI call +// interface (e.g. X86 32 bits). _Complex is not standard C++, so do not use +// it here. +struct c_float_complex_t; +struct c_double_complex_t; + +namespace Fortran::runtime { +class Descriptor; +} + +namespace fir::runtime { + +using TypeBuilderFunc = mlir::Type (*)(mlir::MLIRContext *); +using FuncTypeBuilderFunc = mlir::FunctionType (*)(mlir::MLIRContext *); + +//===----------------------------------------------------------------------===// +// Type builder models +//===----------------------------------------------------------------------===// + +// TODO: all usages of sizeof in this file assume build == host == target. +// This will need to be re-visited for cross compilation. + +/// Return a function that returns the type signature model for the type `T` +/// when provided an MLIRContext*. This allows one to translate C(++) function +/// signatures from runtime header files to MLIR signatures into a static table +/// at compile-time. +/// +/// For example, when `T` is `int`, return a function that returns the MLIR +/// standard type `i32` when `sizeof(int)` is 4. +template +static constexpr TypeBuilderFunc getModel(); +template <> +constexpr TypeBuilderFunc getModel() { + return [](mlir::MLIRContext *context) -> mlir::Type { + return mlir::IntegerType::get(context, 8 * sizeof(short int)); + }; +} +template <> +constexpr TypeBuilderFunc getModel() { + return [](mlir::MLIRContext *context) -> mlir::Type { + return mlir::IntegerType::get(context, 8 * sizeof(int)); + }; +} +template <> +constexpr TypeBuilderFunc getModel() { + return [](mlir::MLIRContext *context) -> mlir::Type { + TypeBuilderFunc f{getModel()}; + return fir::ReferenceType::get(f(context)); + }; +} +template <> +constexpr TypeBuilderFunc getModel() { + return [](mlir::MLIRContext *context) -> mlir::Type { + return fir::ReferenceType::get(mlir::IntegerType::get(context, 8)); + }; +} +template <> +constexpr TypeBuilderFunc getModel() { + return getModel(); +} +template <> +constexpr TypeBuilderFunc getModel() { + return [](mlir::MLIRContext *context) -> mlir::Type { + return fir::ReferenceType::get(mlir::IntegerType::get(context, 16)); + }; +} +template <> +constexpr TypeBuilderFunc getModel() { + return [](mlir::MLIRContext *context) -> mlir::Type { + return fir::ReferenceType::get(mlir::IntegerType::get(context, 32)); + }; +} +template <> +constexpr TypeBuilderFunc getModel() { + return [](mlir::MLIRContext *context) -> mlir::Type { + return mlir::IntegerType::get(context, 8 * sizeof(signed char)); + }; +} +template <> +constexpr TypeBuilderFunc getModel() { + return [](mlir::MLIRContext *context) -> mlir::Type { + return fir::LLVMPointerType::get(mlir::IntegerType::get(context, 8)); + }; +} +template <> +constexpr TypeBuilderFunc getModel() { + return [](mlir::MLIRContext *context) -> mlir::Type { + return fir::ReferenceType::get( + fir::LLVMPointerType::get(mlir::IntegerType::get(context, 8))); + }; +} +template <> +constexpr TypeBuilderFunc getModel() { + return [](mlir::MLIRContext *context) -> mlir::Type { + return mlir::IntegerType::get(context, 8 * sizeof(long)); + }; +} +template <> +constexpr TypeBuilderFunc getModel() { + return [](mlir::MLIRContext *context) -> mlir::Type { + TypeBuilderFunc f{getModel()}; + return fir::ReferenceType::get(f(context)); + }; +} +template <> +constexpr TypeBuilderFunc getModel() { + return getModel(); +} +template <> +constexpr TypeBuilderFunc getModel() { + return [](mlir::MLIRContext *context) -> mlir::Type { + return mlir::IntegerType::get(context, 8 * sizeof(std::size_t)); + }; +} +template <> +constexpr TypeBuilderFunc getModel() { + return [](mlir::MLIRContext *context) -> mlir::Type { + return mlir::IntegerType::get(context, + 8 * sizeof(Fortran::common::int128_t)); + }; +} +template <> +constexpr TypeBuilderFunc getModel() { + return [](mlir::MLIRContext *context) -> mlir::Type { + TypeBuilderFunc f{getModel()}; + return fir::ReferenceType::get(f(context)); + }; +} +template <> +constexpr TypeBuilderFunc getModel() { + return getModel(); +} +template <> +constexpr TypeBuilderFunc getModel() { + return [](mlir::MLIRContext *context) -> mlir::Type { + return mlir::IntegerType::get(context, 8 * sizeof(unsigned long)); + }; +} +template <> +constexpr TypeBuilderFunc getModel() { + return [](mlir::MLIRContext *context) -> mlir::Type { + return mlir::IntegerType::get(context, 8 * sizeof(unsigned long long)); + }; +} +template <> +constexpr TypeBuilderFunc getModel() { + return [](mlir::MLIRContext *context) -> mlir::Type { + return mlir::FloatType::getF64(context); + }; +} +template <> +constexpr TypeBuilderFunc getModel() { + return [](mlir::MLIRContext *context) -> mlir::Type { + TypeBuilderFunc f{getModel()}; + return fir::ReferenceType::get(f(context)); + }; +} +template <> +constexpr TypeBuilderFunc getModel() { + return getModel(); +} +template <> +constexpr TypeBuilderFunc getModel() { + return [](mlir::MLIRContext *context) -> mlir::Type { + return mlir::FloatType::getF32(context); + }; +} +template <> +constexpr TypeBuilderFunc getModel() { + return [](mlir::MLIRContext *context) -> mlir::Type { + TypeBuilderFunc f{getModel()}; + return fir::ReferenceType::get(f(context)); + }; +} +template <> +constexpr TypeBuilderFunc getModel() { + return getModel(); +} +template <> +constexpr TypeBuilderFunc getModel() { + return [](mlir::MLIRContext *context) -> mlir::Type { + return mlir::IntegerType::get(context, 1); + }; +} +template <> +constexpr TypeBuilderFunc getModel() { + return [](mlir::MLIRContext *context) -> mlir::Type { + TypeBuilderFunc f{getModel()}; + return fir::ReferenceType::get(f(context)); + }; +} +template <> +constexpr TypeBuilderFunc getModel &>() { + return [](mlir::MLIRContext *context) -> mlir::Type { + auto ty = mlir::ComplexType::get(mlir::FloatType::getF32(context)); + return fir::ReferenceType::get(ty); + }; +} +template <> +constexpr TypeBuilderFunc getModel &>() { + return [](mlir::MLIRContext *context) -> mlir::Type { + auto ty = mlir::ComplexType::get(mlir::FloatType::getF64(context)); + return fir::ReferenceType::get(ty); + }; +} +template <> +constexpr TypeBuilderFunc getModel() { + return [](mlir::MLIRContext *context) -> mlir::Type { + return fir::ComplexType::get(context, sizeof(float)); + }; +} +template <> +constexpr TypeBuilderFunc getModel() { + return [](mlir::MLIRContext *context) -> mlir::Type { + return fir::ComplexType::get(context, sizeof(double)); + }; +} +template <> +constexpr TypeBuilderFunc getModel() { + return [](mlir::MLIRContext *context) -> mlir::Type { + return fir::BoxType::get(mlir::NoneType::get(context)); + }; +} +template <> +constexpr TypeBuilderFunc getModel() { + return [](mlir::MLIRContext *context) -> mlir::Type { + return fir::ReferenceType::get( + fir::BoxType::get(mlir::NoneType::get(context))); + }; +} +template <> +constexpr TypeBuilderFunc getModel() { + return getModel(); +} +template <> +constexpr TypeBuilderFunc getModel() { + return getModel(); +} +template <> +constexpr TypeBuilderFunc getModel() { + return [](mlir::MLIRContext *context) -> mlir::Type { + return mlir::IntegerType::get(context, + sizeof(Fortran::common::TypeCategory) * 8); + }; +} +template <> +constexpr TypeBuilderFunc getModel() { + return [](mlir::MLIRContext *context) -> mlir::Type { + return mlir::NoneType::get(context); + }; +} + +template +struct RuntimeTableKey; +template +struct RuntimeTableKey { + static constexpr FuncTypeBuilderFunc getTypeModel() { + return [](mlir::MLIRContext *ctxt) { + TypeBuilderFunc ret = getModel(); + std::array args = {getModel()...}; + mlir::Type retTy = ret(ctxt); + llvm::SmallVector argTys; + for (auto f : args) + argTys.push_back(f(ctxt)); + return mlir::FunctionType::get(ctxt, argTys, {retTy}); + }; + } +}; + +//===----------------------------------------------------------------------===// +// Runtime table building (constexpr folded) +//===----------------------------------------------------------------------===// + +template +using RuntimeIdentifier = std::integer_sequence; + +namespace details { +template +static constexpr std::integer_sequence +concat(std::integer_sequence, std::integer_sequence) { + return {}; +} +template +static constexpr auto concat(std::integer_sequence, + std::integer_sequence, Cs...) { + return concat(std::integer_sequence{}, Cs{}...); +} +template +static constexpr std::integer_sequence concat(std::integer_sequence) { + return {}; +} +template +static constexpr auto filterZero(std::integer_sequence) { + if constexpr (a != 0) { + return std::integer_sequence{}; + } else { + return std::integer_sequence{}; + } +} +template +static constexpr auto filter(std::integer_sequence) { + if constexpr (sizeof...(b) > 0) { + return details::concat(filterZero(std::integer_sequence{})...); + } else { + return std::integer_sequence{}; + } +} +} // namespace details + +template +struct RuntimeTableEntry; +template +struct RuntimeTableEntry, RuntimeIdentifier> { + static constexpr FuncTypeBuilderFunc getTypeModel() { + return RuntimeTableKey::getTypeModel(); + } + static constexpr const char name[sizeof...(Cs) + 1] = {Cs..., '\0'}; +}; + +#undef E +#define E(L, I) (I < sizeof(L) / sizeof(*L) ? L[I] : 0) +#define QuoteKey(X) #X +#define ExpandAndQuoteKey(X) QuoteKey(X) +#define MacroExpandKey(X) \ + E(X, 0), E(X, 1), E(X, 2), E(X, 3), E(X, 4), E(X, 5), E(X, 6), E(X, 7), \ + E(X, 8), E(X, 9), E(X, 10), E(X, 11), E(X, 12), E(X, 13), E(X, 14), \ + E(X, 15), E(X, 16), E(X, 17), E(X, 18), E(X, 19), E(X, 20), E(X, 21), \ + E(X, 22), E(X, 23), E(X, 24), E(X, 25), E(X, 26), E(X, 27), E(X, 28), \ + E(X, 29), E(X, 30), E(X, 31), E(X, 32), E(X, 33), E(X, 34), E(X, 35), \ + E(X, 36), E(X, 37), E(X, 38), E(X, 39), E(X, 40), E(X, 41), E(X, 42), \ + E(X, 43), E(X, 44), E(X, 45), E(X, 46), E(X, 47), E(X, 48), E(X, 49) +#define ExpandKey(X) MacroExpandKey(QuoteKey(X)) +#define FullSeq(X) std::integer_sequence +#define AsSequence(X) decltype(fir::runtime::details::filter(FullSeq(X){})) +#define mkKey(X) \ + fir::runtime::RuntimeTableEntry, \ + AsSequence(X)> +#define mkRTKey(X) mkKey(RTNAME(X)) + +/// Get (or generate) the MLIR FuncOp for a given runtime function. Its template +/// argument is intended to be of the form: +/// Clients should add "using namespace Fortran::runtime" +/// in order to use this function. +template +static mlir::FuncOp getRuntimeFunc(mlir::Location loc, + fir::FirOpBuilder &builder) { + auto name = RuntimeEntry::name; + auto func = builder.getNamedFunction(name); + if (func) + return func; + auto funTy = RuntimeEntry::getTypeModel()(builder.getContext()); + func = builder.createFunction(loc, name, funTy); + func->setAttr("fir.runtime", builder.getUnitAttr()); + return func; +} + +namespace helper { +template +void createArguments(llvm::SmallVectorImpl &result, + fir::FirOpBuilder &builder, mlir::Location loc, + mlir::FunctionType fTy, A arg) { + result.emplace_back(builder.createConvert(loc, fTy.getInput(N), arg)); +} + +template +void createArguments(llvm::SmallVectorImpl &result, + fir::FirOpBuilder &builder, mlir::Location loc, + mlir::FunctionType fTy, A arg, As... args) { + result.emplace_back(builder.createConvert(loc, fTy.getInput(N), arg)); + createArguments(result, builder, loc, fTy, args...); +} +} // namespace helper + +/// Create a SmallVector of arguments for a runtime call. +template +llvm::SmallVector +createArguments(fir::FirOpBuilder &builder, mlir::Location loc, + mlir::FunctionType fTy, As... args) { + llvm::SmallVector result; + helper::createArguments<0>(result, builder, loc, fTy, args...); + return result; +} + +} // namespace fir::runtime + +#endif // FORTRAN_OPTIMIZER_BUILDER_RUNTIME_RTBUILDER_H diff --git a/flang/include/flang/Optimizer/Builder/Runtime/Reduction.h b/flang/include/flang/Optimizer/Builder/Runtime/Reduction.h new file mode 100644 --- /dev/null +++ b/flang/include/flang/Optimizer/Builder/Runtime/Reduction.h @@ -0,0 +1,148 @@ +//===-- Reduction.h -- generate calls to reduction runtime API --*- 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_REDUCTION_H +#define FORTRAN_OPTIMIZER_BUILDER_RUNTIME_REDUCTION_H + +#include "mlir/Dialect/StandardOps/IR/Ops.h" + +namespace fir { +class ExtendedValue; +class FirOpBuilder; +} // namespace fir + +namespace fir::runtime { + +/// Generate call to all runtime routine. +/// This calls the descriptor based runtime call implementation of the all +/// intrinsic. +void genAllDescriptor(fir::FirOpBuilder &builder, mlir::Location loc, + mlir::Value resultBox, mlir::Value maskBox, + mlir::Value dim); + +/// Generate call to any runtime routine. +/// This calls the descriptor based runtime call implementation of the any +/// intrinsic. +void genAnyDescriptor(fir::FirOpBuilder &builder, mlir::Location loc, + mlir::Value resultBox, mlir::Value maskBox, + mlir::Value dim); + +/// Generate call to all runtime routine. This version of all is specialized +/// for rank 1 mask arguments. +/// This calls the version that returns a scalar logical value. +mlir::Value genAll(fir::FirOpBuilder &builder, mlir::Location loc, + mlir::Value maskBox, mlir::Value dim); + +/// Generate call to any runtime routine. This version of any is specialized +/// for rank 1 mask arguments. +/// This calls the version that returns a scalar logical value. +mlir::Value genAny(fir::FirOpBuilder &builder, mlir::Location loc, + mlir::Value maskBox, mlir::Value dim); + +/// Generate call to Count runtime routine. This routine is a specialized +/// version when mask is a rank one array or the dim argument is not +/// specified by the user. +mlir::Value genCount(fir::FirOpBuilder &builder, mlir::Location loc, + mlir::Value maskBox, mlir::Value dim); + +/// Generate call to general CountDim runtime routine. This routine has a +/// descriptor result. +void genCountDim(fir::FirOpBuilder &builder, mlir::Location loc, + mlir::Value resultBox, mlir::Value maskBox, mlir::Value dim, + mlir::Value kind); + +/// Generate call to DotProduct intrinsic runtime routine. +mlir::Value genDotProduct(fir::FirOpBuilder &builder, mlir::Location loc, + mlir::Value vectorABox, mlir::Value vectorBBox, + mlir::Value resultBox); + +/// Generate call to Maxloc intrinsic runtime routine. This is the version +/// that does not take a dim argument. +void genMaxloc(fir::FirOpBuilder &builder, mlir::Location loc, + mlir::Value resultBox, mlir::Value arrayBox, mlir::Value maskBox, + mlir::Value kind, mlir::Value back); + +/// Generate call to Maxloc intrinsic runtime routine. This is the version +/// that takes a dim argument. +void genMaxlocDim(fir::FirOpBuilder &builder, mlir::Location loc, + mlir::Value resultBox, mlir::Value arrayBox, mlir::Value dim, + mlir::Value maskBox, mlir::Value kind, mlir::Value back); + +/// Generate call to Minloc intrinsic runtime routine. This is the version +/// that does not take a dim argument. +void genMinloc(fir::FirOpBuilder &builder, mlir::Location loc, + mlir::Value resultBox, mlir::Value arrayBox, mlir::Value maskBox, + mlir::Value kind, mlir::Value back); + +/// Generate call to Minloc intrinsic runtime routine. This is the version +/// that takes a dim argument. +void genMinlocDim(fir::FirOpBuilder &builder, mlir::Location loc, + mlir::Value resultBox, mlir::Value arrayBox, mlir::Value dim, + mlir::Value maskBox, mlir::Value kind, mlir::Value back); + +/// Generate call to Maxval intrinsic runtime routine. This is the version +/// that does not take a dim argument. +mlir::Value genMaxval(fir::FirOpBuilder &builder, mlir::Location loc, + mlir::Value arrayBox, mlir::Value maskBox); + +/// Generate call to Maxval intrinsic runtime routine. This is the version +/// that that handles 1 dimensional character arrays with no DIM argument. +void genMaxvalChar(fir::FirOpBuilder &builder, mlir::Location loc, + mlir::Value resultBox, mlir::Value arrayBox, + mlir::Value maskBox); + +/// Generate call to Maxval intrinsic runtime routine. This is the version +/// that takes arrays of any rank with a dim argument specified. +void genMaxvalDim(fir::FirOpBuilder &builder, mlir::Location loc, + mlir::Value resultBox, mlir::Value arrayBox, mlir::Value dim, + mlir::Value maskBox); + +/// Generate call to Minval intrinsic runtime routine. This is the version +/// that does not take a dim argument. +mlir::Value genMinval(fir::FirOpBuilder &builder, mlir::Location loc, + mlir::Value arrayBox, mlir::Value maskBox); + +/// Generate call to Minval intrinsic runtime routine. This is the version +/// that that handles 1 dimensional character arrays with no DIM argument. +void genMinvalChar(fir::FirOpBuilder &builder, mlir::Location loc, + mlir::Value resultBox, mlir::Value arrayBox, + mlir::Value maskBox); + +/// Generate call to Minval intrinsic runtime routine. This is the version +/// that takes arrays of any rank with a dim argument specified. +void genMinvalDim(fir::FirOpBuilder &builder, mlir::Location loc, + mlir::Value resultBox, mlir::Value arrayBox, mlir::Value dim, + mlir::Value maskBox); + +/// Generate call to Product intrinsic runtime routine. This is the version +/// that does not take a dim argument. +mlir::Value genProduct(fir::FirOpBuilder &builder, mlir::Location loc, + mlir::Value arrayBox, mlir::Value maskBox, + mlir::Value resultBox); + +/// Generate call to Product intrinsic runtime routine. This is the version +/// that takes arrays of any rank with a dim argument specified. +void genProductDim(fir::FirOpBuilder &builder, mlir::Location loc, + mlir::Value resultBox, mlir::Value arrayBox, mlir::Value dim, + mlir::Value maskBox); + +/// Generate call to Sum intrinsic runtime routine. This is the version +/// that does not take a dim argument. +mlir::Value genSum(fir::FirOpBuilder &builder, mlir::Location loc, + mlir::Value arrayBox, mlir::Value maskBox, + mlir::Value resultBox); + +/// Generate call to Sum intrinsic runtime routine. This is the version +/// that takes arrays of any rank with a dim argument specified. +void genSumDim(fir::FirOpBuilder &builder, mlir::Location loc, + mlir::Value resultBox, mlir::Value arrayBox, mlir::Value dim, + mlir::Value maskBox); + +} // namespace fir::runtime + +#endif // FORTRAN_OPTIMIZER_BUILDER_RUNTIME_REDUCTION_H diff --git a/flang/include/flang/Optimizer/Dialect/FIRTypes.td b/flang/include/flang/Optimizer/Dialect/FIRTypes.td --- a/flang/include/flang/Optimizer/Dialect/FIRTypes.td +++ b/flang/include/flang/Optimizer/Dialect/FIRTypes.td @@ -238,6 +238,12 @@ let parameters = (ins "mlir::Type":$eleTy); let assemblyFormat = "`<` $eleTy `>`"; + + let builders = [ + TypeBuilderWithInferredContext<(ins "mlir::Type":$elementType), [{ + return Base::get(elementType.getContext(), elementType); + }]>, + ]; } def fir_PointerType : FIR_Type<"Pointer", "ptr"> { 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/Reduction.cpp DEPENDS FIRDialect diff --git a/flang/lib/Optimizer/Builder/Runtime/Reduction.cpp b/flang/lib/Optimizer/Builder/Runtime/Reduction.cpp new file mode 100644 --- /dev/null +++ b/flang/lib/Optimizer/Builder/Runtime/Reduction.cpp @@ -0,0 +1,927 @@ +//===-- Reduction.cpp -- generate reduction intrinsics runtime calls- -----===// +// +// 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/Reduction.h" +#include "flang/Lower/Todo.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/reduction.h" +#include "mlir/Dialect/StandardOps/IR/Ops.h" + +using namespace Fortran::runtime; + +/// Placeholder for real*10 version of Maxval Intrinsic +struct ForcedMaxvalReal10 { + static constexpr const char *name = ExpandAndQuoteKey(RTNAME(MaxvalReal10)); + static constexpr fir::runtime::FuncTypeBuilderFunc getTypeModel() { + return [](mlir::MLIRContext *ctx) { + auto ty = mlir::FloatType::getF80(ctx); + auto boxTy = + fir::runtime::getModel()(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, {boxTy, strTy, intTy, intTy, boxTy}, + {ty}); + }; + } +}; + +/// Placeholder for real*16 version of Maxval Intrinsic +struct ForcedMaxvalReal16 { + static constexpr const char *name = ExpandAndQuoteKey(RTNAME(MaxvalReal16)); + static constexpr fir::runtime::FuncTypeBuilderFunc getTypeModel() { + return [](mlir::MLIRContext *ctx) { + auto ty = mlir::FloatType::getF128(ctx); + auto boxTy = + fir::runtime::getModel()(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, {boxTy, strTy, intTy, intTy, boxTy}, + {ty}); + }; + } +}; + +/// Placeholder for integer*16 version of Maxval Intrinsic +struct ForcedMaxvalInteger16 { + static constexpr const char *name = + ExpandAndQuoteKey(RTNAME(MaxvalInteger16)); + static constexpr fir::runtime::FuncTypeBuilderFunc getTypeModel() { + return [](mlir::MLIRContext *ctx) { + auto ty = mlir::IntegerType::get(ctx, 128); + auto boxTy = + fir::runtime::getModel()(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, {boxTy, strTy, intTy, intTy, boxTy}, + {ty}); + }; + } +}; + +/// Placeholder for real*10 version of Minval Intrinsic +struct ForcedMinvalReal10 { + static constexpr const char *name = ExpandAndQuoteKey(RTNAME(MinvalReal10)); + static constexpr fir::runtime::FuncTypeBuilderFunc getTypeModel() { + return [](mlir::MLIRContext *ctx) { + auto ty = mlir::FloatType::getF80(ctx); + auto boxTy = + fir::runtime::getModel()(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, {boxTy, strTy, intTy, intTy, boxTy}, + {ty}); + }; + } +}; + +/// Placeholder for real*16 version of Minval Intrinsic +struct ForcedMinvalReal16 { + static constexpr const char *name = ExpandAndQuoteKey(RTNAME(MinvalReal16)); + static constexpr fir::runtime::FuncTypeBuilderFunc getTypeModel() { + return [](mlir::MLIRContext *ctx) { + auto ty = mlir::FloatType::getF128(ctx); + auto boxTy = + fir::runtime::getModel()(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, {boxTy, strTy, intTy, intTy, boxTy}, + {ty}); + }; + } +}; + +/// Placeholder for integer*16 version of Minval Intrinsic +struct ForcedMinvalInteger16 { + static constexpr const char *name = + ExpandAndQuoteKey(RTNAME(MinvalInteger16)); + static constexpr fir::runtime::FuncTypeBuilderFunc getTypeModel() { + return [](mlir::MLIRContext *ctx) { + auto ty = mlir::IntegerType::get(ctx, 128); + auto boxTy = + fir::runtime::getModel()(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, {boxTy, strTy, intTy, intTy, boxTy}, + {ty}); + }; + } +}; + +/// Placeholder for real*10 version of Product Intrinsic +struct ForcedProductReal10 { + static constexpr const char *name = ExpandAndQuoteKey(RTNAME(ProductReal10)); + static constexpr fir::runtime::FuncTypeBuilderFunc getTypeModel() { + return [](mlir::MLIRContext *ctx) { + auto ty = mlir::FloatType::getF80(ctx); + auto boxTy = + fir::runtime::getModel()(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, {boxTy, strTy, intTy, intTy, boxTy}, + {ty}); + }; + } +}; + +/// Placeholder for real*16 version of Product Intrinsic +struct ForcedProductReal16 { + static constexpr const char *name = ExpandAndQuoteKey(RTNAME(ProductReal16)); + static constexpr fir::runtime::FuncTypeBuilderFunc getTypeModel() { + return [](mlir::MLIRContext *ctx) { + auto ty = mlir::FloatType::getF128(ctx); + auto boxTy = + fir::runtime::getModel()(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, {boxTy, strTy, intTy, intTy, boxTy}, + {ty}); + }; + } +}; + +/// Placeholder for integer*16 version of Product Intrinsic +struct ForcedProductInteger16 { + static constexpr const char *name = + ExpandAndQuoteKey(RTNAME(ProductInteger16)); + static constexpr fir::runtime::FuncTypeBuilderFunc getTypeModel() { + return [](mlir::MLIRContext *ctx) { + auto ty = mlir::IntegerType::get(ctx, 128); + auto boxTy = + fir::runtime::getModel()(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, {boxTy, strTy, intTy, intTy, boxTy}, + {ty}); + }; + } +}; + +/// Placeholder for complex(10) version of Product Intrinsic +struct ForcedProductComplex10 { + static constexpr const char *name = + ExpandAndQuoteKey(RTNAME(CppProductComplex10)); + static constexpr fir::runtime::FuncTypeBuilderFunc getTypeModel() { + return [](mlir::MLIRContext *ctx) { + auto ty = mlir::ComplexType::get(mlir::FloatType::getF80(ctx)); + auto boxTy = + fir::runtime::getModel()(ctx); + auto strTy = fir::ReferenceType::get(mlir::IntegerType::get(ctx, 8)); + auto intTy = mlir::IntegerType::get(ctx, 8 * sizeof(int)); + auto resTy = fir::ReferenceType::get(ty); + return mlir::FunctionType::get( + ctx, {resTy, boxTy, strTy, intTy, intTy, boxTy}, {}); + }; + } +}; + +/// Placeholder for complex(16) version of Product Intrinsic +struct ForcedProductComplex16 { + static constexpr const char *name = + ExpandAndQuoteKey(RTNAME(CppProductComplex16)); + static constexpr fir::runtime::FuncTypeBuilderFunc getTypeModel() { + return [](mlir::MLIRContext *ctx) { + auto ty = mlir::ComplexType::get(mlir::FloatType::getF128(ctx)); + auto boxTy = + fir::runtime::getModel()(ctx); + auto strTy = fir::ReferenceType::get(mlir::IntegerType::get(ctx, 8)); + auto intTy = mlir::IntegerType::get(ctx, 8 * sizeof(int)); + auto resTy = fir::ReferenceType::get(ty); + return mlir::FunctionType::get( + ctx, {resTy, boxTy, strTy, intTy, intTy, boxTy}, {}); + }; + } +}; + +/// Placeholder for real*10 version of DotProduct Intrinsic +struct ForcedDotProductReal10 { + static constexpr const char *name = + ExpandAndQuoteKey(RTNAME(DotProductReal10)); + static constexpr fir::runtime::FuncTypeBuilderFunc getTypeModel() { + return [](mlir::MLIRContext *ctx) { + auto ty = mlir::FloatType::getF80(ctx); + auto boxTy = + fir::runtime::getModel()(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, {boxTy, boxTy, strTy, intTy}, {ty}); + }; + } +}; + +/// Placeholder for real*16 version of DotProduct Intrinsic +struct ForcedDotProductReal16 { + static constexpr const char *name = + ExpandAndQuoteKey(RTNAME(DotProductReal16)); + static constexpr fir::runtime::FuncTypeBuilderFunc getTypeModel() { + return [](mlir::MLIRContext *ctx) { + auto ty = mlir::FloatType::getF128(ctx); + auto boxTy = + fir::runtime::getModel()(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, {boxTy, boxTy, strTy, intTy}, {ty}); + }; + } +}; + +/// Placeholder for complex(10) version of DotProduct Intrinsic +struct ForcedDotProductComplex10 { + static constexpr const char *name = + ExpandAndQuoteKey(RTNAME(CppDotProductComplex10)); + static constexpr fir::runtime::FuncTypeBuilderFunc getTypeModel() { + return [](mlir::MLIRContext *ctx) { + auto ty = mlir::ComplexType::get(mlir::FloatType::getF80(ctx)); + auto boxTy = + fir::runtime::getModel()(ctx); + auto strTy = fir::ReferenceType::get(mlir::IntegerType::get(ctx, 8)); + auto intTy = mlir::IntegerType::get(ctx, 8 * sizeof(int)); + auto resTy = fir::ReferenceType::get(ty); + return mlir::FunctionType::get(ctx, {resTy, boxTy, boxTy, strTy, intTy}, + {}); + }; + } +}; + +/// Placeholder for complex(16) version of DotProduct Intrinsic +struct ForcedDotProductComplex16 { + static constexpr const char *name = + ExpandAndQuoteKey(RTNAME(CppDotProductComplex16)); + static constexpr fir::runtime::FuncTypeBuilderFunc getTypeModel() { + return [](mlir::MLIRContext *ctx) { + auto ty = mlir::ComplexType::get(mlir::FloatType::getF128(ctx)); + auto boxTy = + fir::runtime::getModel()(ctx); + auto strTy = fir::ReferenceType::get(mlir::IntegerType::get(ctx, 8)); + auto intTy = mlir::IntegerType::get(ctx, 8 * sizeof(int)); + auto resTy = fir::ReferenceType::get(ty); + return mlir::FunctionType::get(ctx, {resTy, boxTy, boxTy, strTy, intTy}, + {}); + }; + } +}; + +/// Placeholder for integer*16 version of DotProduct Intrinsic +struct ForcedDotProductInteger16 { + static constexpr const char *name = + ExpandAndQuoteKey(RTNAME(DotProductInteger16)); + static constexpr fir::runtime::FuncTypeBuilderFunc getTypeModel() { + return [](mlir::MLIRContext *ctx) { + auto ty = mlir::IntegerType::get(ctx, 128); + auto boxTy = + fir::runtime::getModel()(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, {boxTy, boxTy, strTy, intTy}, {ty}); + }; + } +}; + +/// Placeholder for real*10 version of Sum Intrinsic +struct ForcedSumReal10 { + static constexpr const char *name = ExpandAndQuoteKey(RTNAME(SumReal10)); + static constexpr fir::runtime::FuncTypeBuilderFunc getTypeModel() { + return [](mlir::MLIRContext *ctx) { + auto ty = mlir::FloatType::getF80(ctx); + auto boxTy = + fir::runtime::getModel()(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, {boxTy, strTy, intTy, intTy, boxTy}, + {ty}); + }; + } +}; + +/// Placeholder for real*16 version of Sum Intrinsic +struct ForcedSumReal16 { + static constexpr const char *name = ExpandAndQuoteKey(RTNAME(SumReal16)); + static constexpr fir::runtime::FuncTypeBuilderFunc getTypeModel() { + return [](mlir::MLIRContext *ctx) { + auto ty = mlir::FloatType::getF128(ctx); + auto boxTy = + fir::runtime::getModel()(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, {boxTy, strTy, intTy, intTy, boxTy}, + {ty}); + }; + } +}; + +/// Placeholder for integer*16 version of Sum Intrinsic +struct ForcedSumInteger16 { + static constexpr const char *name = ExpandAndQuoteKey(RTNAME(SumInteger16)); + static constexpr fir::runtime::FuncTypeBuilderFunc getTypeModel() { + return [](mlir::MLIRContext *ctx) { + auto ty = mlir::IntegerType::get(ctx, 128); + auto boxTy = + fir::runtime::getModel()(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, {boxTy, strTy, intTy, intTy, boxTy}, + {ty}); + }; + } +}; + +/// Placeholder for complex(10) version of Sum Intrinsic +struct ForcedSumComplex10 { + static constexpr const char *name = + ExpandAndQuoteKey(RTNAME(CppSumComplex10)); + static constexpr fir::runtime::FuncTypeBuilderFunc getTypeModel() { + return [](mlir::MLIRContext *ctx) { + auto ty = mlir::ComplexType::get(mlir::FloatType::getF80(ctx)); + auto boxTy = + fir::runtime::getModel()(ctx); + auto strTy = fir::ReferenceType::get(mlir::IntegerType::get(ctx, 8)); + auto intTy = mlir::IntegerType::get(ctx, 8 * sizeof(int)); + auto resTy = fir::ReferenceType::get(ty); + return mlir::FunctionType::get( + ctx, {resTy, boxTy, strTy, intTy, intTy, boxTy}, {}); + }; + } +}; + +/// Placeholder for complex(16) version of Sum Intrinsic +struct ForcedSumComplex16 { + static constexpr const char *name = + ExpandAndQuoteKey(RTNAME(CppSumComplex16)); + static constexpr fir::runtime::FuncTypeBuilderFunc getTypeModel() { + return [](mlir::MLIRContext *ctx) { + auto ty = mlir::ComplexType::get(mlir::FloatType::getF128(ctx)); + auto boxTy = + fir::runtime::getModel()(ctx); + auto strTy = fir::ReferenceType::get(mlir::IntegerType::get(ctx, 8)); + auto intTy = mlir::IntegerType::get(ctx, 8 * sizeof(int)); + auto resTy = fir::ReferenceType::get(ty); + return mlir::FunctionType::get( + ctx, {resTy, boxTy, strTy, intTy, intTy, boxTy}, {}); + }; + } +}; + +/// Generate call to specialized runtime function that takes a mask and +/// dim argument. The All, Any, and Count intrinsics use this pattern. +template +mlir::Value genSpecial2Args(FN func, fir::FirOpBuilder &builder, + mlir::Location loc, mlir::Value maskBox, + mlir::Value dim) { + auto fTy = func.getType(); + auto sourceFile = fir::factory::locationToFilename(builder, loc); + auto sourceLine = + fir::factory::locationToLineNo(builder, loc, fTy.getInput(2)); + auto args = fir::runtime::createArguments(builder, loc, fTy, maskBox, + sourceFile, sourceLine, dim); + return builder.create(loc, func, args).getResult(0); +} + +/// Generate calls to reduction intrinsics such as All and Any. +/// These are the descriptor based implementations that take two +/// arguments (mask, dim). +template +static void genReduction2Args(FN func, fir::FirOpBuilder &builder, + mlir::Location loc, mlir::Value resultBox, + mlir::Value maskBox, mlir::Value dim) { + auto fTy = func.getType(); + auto sourceFile = fir::factory::locationToFilename(builder, loc); + auto sourceLine = + fir::factory::locationToLineNo(builder, loc, fTy.getInput(4)); + auto args = fir::runtime::createArguments( + builder, loc, fTy, resultBox, maskBox, dim, sourceFile, sourceLine); + builder.create(loc, func, args); +} + +/// Generate calls to reduction intrinsics such as Maxval and Minval. +/// These take arguments such as (array, dim, mask). +template +static void genReduction3Args(FN func, fir::FirOpBuilder &builder, + mlir::Location loc, mlir::Value resultBox, + mlir::Value arrayBox, mlir::Value dim, + mlir::Value maskBox) { + + auto fTy = func.getType(); + auto sourceFile = fir::factory::locationToFilename(builder, loc); + auto sourceLine = + fir::factory::locationToLineNo(builder, loc, fTy.getInput(4)); + auto args = + fir::runtime::createArguments(builder, loc, fTy, resultBox, arrayBox, dim, + sourceFile, sourceLine, maskBox); + builder.create(loc, func, args); +} + +/// Generate calls to reduction intrinsics such as Maxloc and Minloc. +/// These take arguments such as (array, mask, kind, back). +template +static void genReduction4Args(FN func, fir::FirOpBuilder &builder, + mlir::Location loc, mlir::Value resultBox, + mlir::Value arrayBox, mlir::Value maskBox, + mlir::Value kind, mlir::Value back) { + auto fTy = func.getType(); + auto sourceFile = fir::factory::locationToFilename(builder, loc); + auto sourceLine = + fir::factory::locationToLineNo(builder, loc, fTy.getInput(4)); + auto args = fir::runtime::createArguments(builder, loc, fTy, resultBox, + arrayBox, kind, sourceFile, + sourceLine, maskBox, back); + builder.create(loc, func, args); +} + +/// Generate calls to reduction intrinsics such as Maxloc and Minloc. +/// These take arguments such as (array, dim, mask, kind, back). +template +static void +genReduction5Args(FN func, fir::FirOpBuilder &builder, mlir::Location loc, + mlir::Value resultBox, mlir::Value arrayBox, mlir::Value dim, + mlir::Value maskBox, mlir::Value kind, mlir::Value back) { + auto fTy = func.getType(); + auto sourceFile = fir::factory::locationToFilename(builder, loc); + auto sourceLine = + fir::factory::locationToLineNo(builder, loc, fTy.getInput(5)); + auto args = fir::runtime::createArguments(builder, loc, fTy, resultBox, + arrayBox, kind, dim, sourceFile, + sourceLine, maskBox, back); + builder.create(loc, func, args); +} + +/// Generate call to all runtime routine. +/// This calls the descriptor based runtime call implementation of the all +/// intrinsic. +void fir::runtime::genAllDescriptor(fir::FirOpBuilder &builder, + mlir::Location loc, mlir::Value resultBox, + mlir::Value maskBox, mlir::Value dim) { + auto allFunc = fir::runtime::getRuntimeFunc(loc, builder); + genReduction2Args(allFunc, builder, loc, resultBox, maskBox, dim); +} + +/// Generate call to any runtime routine. +/// This calls the descriptor based runtime call implementation of the any +/// intrinsic. +void fir::runtime::genAnyDescriptor(fir::FirOpBuilder &builder, + mlir::Location loc, mlir::Value resultBox, + mlir::Value maskBox, mlir::Value dim) { + auto anyFunc = fir::runtime::getRuntimeFunc(loc, builder); + genReduction2Args(anyFunc, builder, loc, resultBox, maskBox, dim); +} + +/// Generate call to All intrinsic runtime routine. This routine is +/// specialized for mask arguments with rank == 1. +mlir::Value fir::runtime::genAll(fir::FirOpBuilder &builder, mlir::Location loc, + mlir::Value maskBox, mlir::Value dim) { + auto allFunc = fir::runtime::getRuntimeFunc(loc, builder); + return genSpecial2Args(allFunc, builder, loc, maskBox, dim); +} + +/// Generate call to Any intrinsic runtime routine. This routine is +/// specialized for mask arguments with rank == 1. +mlir::Value fir::runtime::genAny(fir::FirOpBuilder &builder, mlir::Location loc, + mlir::Value maskBox, mlir::Value dim) { + auto anyFunc = fir::runtime::getRuntimeFunc(loc, builder); + return genSpecial2Args(anyFunc, builder, loc, maskBox, dim); +} + +/// Generate call to Count runtime routine. This routine is a specialized +/// version when mask is a rank one array or the dim argument is not +/// specified by the user. +mlir::Value fir::runtime::genCount(fir::FirOpBuilder &builder, + mlir::Location loc, mlir::Value maskBox, + mlir::Value dim) { + auto countFunc = fir::runtime::getRuntimeFunc(loc, builder); + return genSpecial2Args(countFunc, builder, loc, maskBox, dim); +} + +/// Generate call to general CountDim runtime routine. This routine has a +/// descriptor result. +void fir::runtime::genCountDim(fir::FirOpBuilder &builder, mlir::Location loc, + mlir::Value resultBox, mlir::Value maskBox, + mlir::Value dim, mlir::Value kind) { + auto func = fir::runtime::getRuntimeFunc(loc, builder); + auto fTy = func.getType(); + auto sourceFile = fir::factory::locationToFilename(builder, loc); + auto sourceLine = + fir::factory::locationToLineNo(builder, loc, fTy.getInput(5)); + auto args = fir::runtime::createArguments( + builder, loc, fTy, resultBox, maskBox, dim, kind, sourceFile, sourceLine); + builder.create(loc, func, args); +} + +/// Generate call to Maxloc intrinsic runtime routine. This is the version +/// that does not take a dim argument. +void fir::runtime::genMaxloc(fir::FirOpBuilder &builder, mlir::Location loc, + mlir::Value resultBox, mlir::Value arrayBox, + mlir::Value maskBox, mlir::Value kind, + mlir::Value back) { + auto func = fir::runtime::getRuntimeFunc(loc, builder); + genReduction4Args(func, builder, loc, resultBox, arrayBox, maskBox, kind, + back); +} + +/// Generate call to Maxloc intrinsic runtime routine. This is the version +/// that takes a dim argument. +void fir::runtime::genMaxlocDim(fir::FirOpBuilder &builder, mlir::Location loc, + mlir::Value resultBox, mlir::Value arrayBox, + mlir::Value dim, mlir::Value maskBox, + mlir::Value kind, mlir::Value back) { + auto func = fir::runtime::getRuntimeFunc(loc, builder); + genReduction5Args(func, builder, loc, resultBox, arrayBox, dim, maskBox, kind, + back); +} + +/// Generate call to Maxval intrinsic runtime routine. This is the version +/// that does not take a dim argument. +mlir::Value fir::runtime::genMaxval(fir::FirOpBuilder &builder, + mlir::Location loc, mlir::Value arrayBox, + mlir::Value maskBox) { + mlir::FuncOp func; + auto ty = arrayBox.getType(); + auto arrTy = fir::dyn_cast_ptrOrBoxEleTy(ty); + auto eleTy = arrTy.cast().getEleTy(); + auto dim = builder.createIntegerConstant(loc, builder.getIndexType(), 0); + + if (eleTy.isF32()) + func = fir::runtime::getRuntimeFunc(loc, builder); + else if (eleTy.isF64()) + func = fir::runtime::getRuntimeFunc(loc, builder); + else if (eleTy.isF80()) + func = fir::runtime::getRuntimeFunc(loc, builder); + else if (eleTy.isF128()) + func = fir::runtime::getRuntimeFunc(loc, builder); + else if (eleTy == + builder.getIntegerType(builder.getKindMap().getIntegerBitsize(1))) + func = fir::runtime::getRuntimeFunc(loc, builder); + else if (eleTy == + builder.getIntegerType(builder.getKindMap().getIntegerBitsize(2))) + func = fir::runtime::getRuntimeFunc(loc, builder); + else if (eleTy == + builder.getIntegerType(builder.getKindMap().getIntegerBitsize(4))) + func = fir::runtime::getRuntimeFunc(loc, builder); + else if (eleTy == + builder.getIntegerType(builder.getKindMap().getIntegerBitsize(8))) + func = fir::runtime::getRuntimeFunc(loc, builder); + else if (eleTy == + builder.getIntegerType(builder.getKindMap().getIntegerBitsize(16))) + func = fir::runtime::getRuntimeFunc(loc, builder); + else + fir::emitFatalError(loc, "invalid type in Maxval lowering"); + + auto fTy = func.getType(); + auto sourceFile = fir::factory::locationToFilename(builder, loc); + auto sourceLine = + fir::factory::locationToLineNo(builder, loc, fTy.getInput(2)); + auto args = fir::runtime::createArguments( + builder, loc, fTy, arrayBox, sourceFile, sourceLine, dim, maskBox); + + return builder.create(loc, func, args).getResult(0); +} + +/// Generate call to Maxval intrinsic runtime routine. This is the version +/// that handles any rank array with the dim argument specified. +void fir::runtime::genMaxvalDim(fir::FirOpBuilder &builder, mlir::Location loc, + mlir::Value resultBox, mlir::Value arrayBox, + mlir::Value dim, mlir::Value maskBox) { + auto func = fir::runtime::getRuntimeFunc(loc, builder); + genReduction3Args(func, builder, loc, resultBox, arrayBox, dim, maskBox); +} + +/// Generate call to Maxval intrinsic runtime routine. This is the version +/// that handles character arrays of rank 1 and without a DIM argument. +void fir::runtime::genMaxvalChar(fir::FirOpBuilder &builder, mlir::Location loc, + mlir::Value resultBox, mlir::Value arrayBox, + mlir::Value maskBox) { + auto func = + fir::runtime::getRuntimeFunc(loc, builder); + auto fTy = func.getType(); + auto sourceFile = fir::factory::locationToFilename(builder, loc); + auto sourceLine = + fir::factory::locationToLineNo(builder, loc, fTy.getInput(3)); + auto args = fir::runtime::createArguments( + builder, loc, fTy, resultBox, arrayBox, sourceFile, sourceLine, maskBox); + builder.create(loc, func, args); +} + +/// Generate call to Minloc intrinsic runtime routine. This is the version +/// that does not take a dim argument. +void fir::runtime::genMinloc(fir::FirOpBuilder &builder, mlir::Location loc, + mlir::Value resultBox, mlir::Value arrayBox, + mlir::Value maskBox, mlir::Value kind, + mlir::Value back) { + auto func = fir::runtime::getRuntimeFunc(loc, builder); + genReduction4Args(func, builder, loc, resultBox, arrayBox, maskBox, kind, + back); +} + +/// Generate call to Minloc intrinsic runtime routine. This is the version +/// that takes a dim argument. +void fir::runtime::genMinlocDim(fir::FirOpBuilder &builder, mlir::Location loc, + mlir::Value resultBox, mlir::Value arrayBox, + mlir::Value dim, mlir::Value maskBox, + mlir::Value kind, mlir::Value back) { + auto func = fir::runtime::getRuntimeFunc(loc, builder); + genReduction5Args(func, builder, loc, resultBox, arrayBox, dim, maskBox, kind, + back); +} + +/// Generate call to Minval intrinsic runtime routine. This is the version +/// that handles any rank array with the dim argument specified. +void fir::runtime::genMinvalDim(fir::FirOpBuilder &builder, mlir::Location loc, + mlir::Value resultBox, mlir::Value arrayBox, + mlir::Value dim, mlir::Value maskBox) { + auto func = fir::runtime::getRuntimeFunc(loc, builder); + genReduction3Args(func, builder, loc, resultBox, arrayBox, dim, maskBox); +} + +/// Generate call to Minval intrinsic runtime routine. This is the version +/// that handles character arrays of rank 1 and without a DIM argument. +void fir::runtime::genMinvalChar(fir::FirOpBuilder &builder, mlir::Location loc, + mlir::Value resultBox, mlir::Value arrayBox, + mlir::Value maskBox) { + auto func = + fir::runtime::getRuntimeFunc(loc, builder); + auto fTy = func.getType(); + auto sourceFile = fir::factory::locationToFilename(builder, loc); + auto sourceLine = + fir::factory::locationToLineNo(builder, loc, fTy.getInput(3)); + auto args = fir::runtime::createArguments( + builder, loc, fTy, resultBox, arrayBox, sourceFile, sourceLine, maskBox); + builder.create(loc, func, args); +} + +/// Generate call to Minval intrinsic runtime routine. This is the version +/// that does not take a dim argument. +mlir::Value fir::runtime::genMinval(fir::FirOpBuilder &builder, + mlir::Location loc, mlir::Value arrayBox, + mlir::Value maskBox) { + mlir::FuncOp func; + auto ty = arrayBox.getType(); + auto arrTy = fir::dyn_cast_ptrOrBoxEleTy(ty); + auto eleTy = arrTy.cast().getEleTy(); + auto dim = builder.createIntegerConstant(loc, builder.getIndexType(), 0); + + if (eleTy.isF32()) + func = fir::runtime::getRuntimeFunc(loc, builder); + else if (eleTy.isF64()) + func = fir::runtime::getRuntimeFunc(loc, builder); + else if (eleTy.isF80()) + func = fir::runtime::getRuntimeFunc(loc, builder); + else if (eleTy.isF128()) + func = fir::runtime::getRuntimeFunc(loc, builder); + else if (eleTy == + builder.getIntegerType(builder.getKindMap().getIntegerBitsize(1))) + func = fir::runtime::getRuntimeFunc(loc, builder); + else if (eleTy == + builder.getIntegerType(builder.getKindMap().getIntegerBitsize(2))) + func = fir::runtime::getRuntimeFunc(loc, builder); + else if (eleTy == + builder.getIntegerType(builder.getKindMap().getIntegerBitsize(4))) + func = fir::runtime::getRuntimeFunc(loc, builder); + else if (eleTy == + builder.getIntegerType(builder.getKindMap().getIntegerBitsize(8))) + func = fir::runtime::getRuntimeFunc(loc, builder); + else if (eleTy == + builder.getIntegerType(builder.getKindMap().getIntegerBitsize(16))) + func = fir::runtime::getRuntimeFunc(loc, builder); + else + fir::emitFatalError(loc, "invalid type in Minval lowering"); + + auto fTy = func.getType(); + auto sourceFile = fir::factory::locationToFilename(builder, loc); + auto sourceLine = + fir::factory::locationToLineNo(builder, loc, fTy.getInput(2)); + auto args = fir::runtime::createArguments( + builder, loc, fTy, arrayBox, sourceFile, sourceLine, dim, maskBox); + + return builder.create(loc, func, args).getResult(0); +} + +/// Generate call to Product intrinsic runtime routine. This is the version +/// that handles any rank array with the dim argument specified. +void fir::runtime::genProductDim(fir::FirOpBuilder &builder, mlir::Location loc, + mlir::Value resultBox, mlir::Value arrayBox, + mlir::Value dim, mlir::Value maskBox) { + auto func = fir::runtime::getRuntimeFunc(loc, builder); + genReduction3Args(func, builder, loc, resultBox, arrayBox, dim, maskBox); +} + +/// Generate call to Product intrinsic runtime routine. This is the version +/// that does not take a dim argument. +mlir::Value fir::runtime::genProduct(fir::FirOpBuilder &builder, + mlir::Location loc, mlir::Value arrayBox, + mlir::Value maskBox, + mlir::Value resultBox) { + mlir::FuncOp func; + auto ty = arrayBox.getType(); + auto arrTy = fir::dyn_cast_ptrOrBoxEleTy(ty); + auto eleTy = arrTy.cast().getEleTy(); + auto dim = builder.createIntegerConstant(loc, builder.getIndexType(), 0); + + if (eleTy.isF32()) + func = fir::runtime::getRuntimeFunc(loc, builder); + else if (eleTy.isF64()) + func = fir::runtime::getRuntimeFunc(loc, builder); + else if (eleTy.isF80()) + func = fir::runtime::getRuntimeFunc(loc, builder); + else if (eleTy.isF128()) + func = fir::runtime::getRuntimeFunc(loc, builder); + else if (eleTy == + builder.getIntegerType(builder.getKindMap().getIntegerBitsize(1))) + func = fir::runtime::getRuntimeFunc(loc, builder); + else if (eleTy == + builder.getIntegerType(builder.getKindMap().getIntegerBitsize(2))) + func = fir::runtime::getRuntimeFunc(loc, builder); + else if (eleTy == + builder.getIntegerType(builder.getKindMap().getIntegerBitsize(4))) + func = fir::runtime::getRuntimeFunc(loc, builder); + else if (eleTy == + builder.getIntegerType(builder.getKindMap().getIntegerBitsize(8))) + func = fir::runtime::getRuntimeFunc(loc, builder); + else if (eleTy == + builder.getIntegerType(builder.getKindMap().getIntegerBitsize(16))) + func = fir::runtime::getRuntimeFunc(loc, builder); + else if (eleTy == fir::ComplexType::get(builder.getContext(), 4)) + func = + fir::runtime::getRuntimeFunc(loc, builder); + else if (eleTy == fir::ComplexType::get(builder.getContext(), 8)) + func = + fir::runtime::getRuntimeFunc(loc, builder); + else if (eleTy == fir::ComplexType::get(builder.getContext(), 10)) + func = fir::runtime::getRuntimeFunc(loc, builder); + else if (eleTy == fir::ComplexType::get(builder.getContext(), 16)) + func = fir::runtime::getRuntimeFunc(loc, builder); + else + fir::emitFatalError(loc, "invalid type in Product lowering"); + + auto fTy = func.getType(); + auto sourceFile = fir::factory::locationToFilename(builder, loc); + if (fir::isa_complex(eleTy)) { + auto sourceLine = + fir::factory::locationToLineNo(builder, loc, fTy.getInput(3)); + auto args = + fir::runtime::createArguments(builder, loc, fTy, resultBox, arrayBox, + sourceFile, sourceLine, dim, maskBox); + builder.create(loc, func, args); + return resultBox; + } + + auto sourceLine = + fir::factory::locationToLineNo(builder, loc, fTy.getInput(2)); + auto args = fir::runtime::createArguments( + builder, loc, fTy, arrayBox, sourceFile, sourceLine, dim, maskBox); + + return builder.create(loc, func, args).getResult(0); +} + +mlir::Value fir::runtime::genDotProduct(fir::FirOpBuilder &builder, + mlir::Location loc, + mlir::Value vectorABox, + mlir::Value vectorBBox, + mlir::Value resultBox) { + mlir::FuncOp func; + auto ty = vectorABox.getType(); + auto arrTy = fir::dyn_cast_ptrOrBoxEleTy(ty); + auto eleTy = arrTy.cast().getEleTy(); + + if (eleTy.isF32()) + func = fir::runtime::getRuntimeFunc(loc, builder); + else if (eleTy.isF64()) + func = fir::runtime::getRuntimeFunc(loc, builder); + else if (eleTy.isF80()) + func = fir::runtime::getRuntimeFunc(loc, builder); + else if (eleTy.isF128()) + func = fir::runtime::getRuntimeFunc(loc, builder); + else if (eleTy == fir::ComplexType::get(builder.getContext(), 4)) + func = fir::runtime::getRuntimeFunc( + loc, builder); + else if (eleTy == fir::ComplexType::get(builder.getContext(), 8)) + func = fir::runtime::getRuntimeFunc( + loc, builder); + else if (eleTy == fir::ComplexType::get(builder.getContext(), 10)) + func = + fir::runtime::getRuntimeFunc(loc, builder); + else if (eleTy == fir::ComplexType::get(builder.getContext(), 16)) + func = + fir::runtime::getRuntimeFunc(loc, builder); + else if (eleTy == + builder.getIntegerType(builder.getKindMap().getIntegerBitsize(1))) + func = + fir::runtime::getRuntimeFunc(loc, builder); + else if (eleTy == + builder.getIntegerType(builder.getKindMap().getIntegerBitsize(2))) + func = + fir::runtime::getRuntimeFunc(loc, builder); + else if (eleTy == + builder.getIntegerType(builder.getKindMap().getIntegerBitsize(4))) + func = + fir::runtime::getRuntimeFunc(loc, builder); + else if (eleTy == + builder.getIntegerType(builder.getKindMap().getIntegerBitsize(8))) + func = + fir::runtime::getRuntimeFunc(loc, builder); + else if (eleTy == + builder.getIntegerType(builder.getKindMap().getIntegerBitsize(16))) + func = + fir::runtime::getRuntimeFunc(loc, builder); + else if (eleTy.isa()) + func = + fir::runtime::getRuntimeFunc(loc, builder); + else + fir::emitFatalError(loc, "invalid type in DotProduct lowering"); + + auto fTy = func.getType(); + auto sourceFile = fir::factory::locationToFilename(builder, loc); + + if (fir::isa_complex(eleTy)) { + auto sourceLine = + fir::factory::locationToLineNo(builder, loc, fTy.getInput(4)); + auto args = + fir::runtime::createArguments(builder, loc, fTy, resultBox, vectorABox, + vectorBBox, sourceFile, sourceLine); + builder.create(loc, func, args); + return resultBox; + } + + auto sourceLine = + fir::factory::locationToLineNo(builder, loc, fTy.getInput(3)); + auto args = fir::runtime::createArguments(builder, loc, fTy, vectorABox, + vectorBBox, sourceFile, sourceLine); + return builder.create(loc, func, args).getResult(0); +} +/// Generate call to Sum intrinsic runtime routine. This is the version +/// that handles any rank array with the dim argument specified. +void fir::runtime::genSumDim(fir::FirOpBuilder &builder, mlir::Location loc, + mlir::Value resultBox, mlir::Value arrayBox, + mlir::Value dim, mlir::Value maskBox) { + auto func = fir::runtime::getRuntimeFunc(loc, builder); + genReduction3Args(func, builder, loc, resultBox, arrayBox, dim, maskBox); +} + +/// Generate call to Sum intrinsic runtime routine. This is the version +/// that does not take a dim argument. +mlir::Value fir::runtime::genSum(fir::FirOpBuilder &builder, mlir::Location loc, + mlir::Value arrayBox, mlir::Value maskBox, + mlir::Value resultBox) { + mlir::FuncOp func; + auto ty = arrayBox.getType(); + auto arrTy = fir::dyn_cast_ptrOrBoxEleTy(ty); + auto eleTy = arrTy.cast().getEleTy(); + auto dim = builder.createIntegerConstant(loc, builder.getIndexType(), 0); + + if (eleTy.isF32()) + func = fir::runtime::getRuntimeFunc(loc, builder); + else if (eleTy.isF64()) + func = fir::runtime::getRuntimeFunc(loc, builder); + else if (eleTy.isF80()) + func = fir::runtime::getRuntimeFunc(loc, builder); + else if (eleTy.isF128()) + func = fir::runtime::getRuntimeFunc(loc, builder); + else if (eleTy == + builder.getIntegerType(builder.getKindMap().getIntegerBitsize(1))) + func = fir::runtime::getRuntimeFunc(loc, builder); + else if (eleTy == + builder.getIntegerType(builder.getKindMap().getIntegerBitsize(2))) + func = fir::runtime::getRuntimeFunc(loc, builder); + else if (eleTy == + builder.getIntegerType(builder.getKindMap().getIntegerBitsize(4))) + func = fir::runtime::getRuntimeFunc(loc, builder); + else if (eleTy == + builder.getIntegerType(builder.getKindMap().getIntegerBitsize(8))) + func = fir::runtime::getRuntimeFunc(loc, builder); + else if (eleTy == + builder.getIntegerType(builder.getKindMap().getIntegerBitsize(16))) + func = fir::runtime::getRuntimeFunc(loc, builder); + else if (eleTy == fir::ComplexType::get(builder.getContext(), 4)) + func = fir::runtime::getRuntimeFunc(loc, builder); + else if (eleTy == fir::ComplexType::get(builder.getContext(), 8)) + func = fir::runtime::getRuntimeFunc(loc, builder); + else if (eleTy == fir::ComplexType::get(builder.getContext(), 10)) + func = fir::runtime::getRuntimeFunc(loc, builder); + else if (eleTy == fir::ComplexType::get(builder.getContext(), 16)) + func = fir::runtime::getRuntimeFunc(loc, builder); + else + fir::emitFatalError(loc, "invalid type in Sum lowering"); + + auto fTy = func.getType(); + auto sourceFile = fir::factory::locationToFilename(builder, loc); + if (fir::isa_complex(eleTy)) { + auto sourceLine = + fir::factory::locationToLineNo(builder, loc, fTy.getInput(3)); + auto args = + fir::runtime::createArguments(builder, loc, fTy, resultBox, arrayBox, + sourceFile, sourceLine, dim, maskBox); + builder.create(loc, func, args); + return resultBox; + } + + auto sourceLine = + fir::factory::locationToLineNo(builder, loc, fTy.getInput(2)); + auto args = fir::runtime::createArguments( + builder, loc, fTy, arrayBox, sourceFile, sourceLine, dim, maskBox); + + return builder.create(loc, func, args).getResult(0); +} diff --git a/flang/unittests/Optimizer/Builder/Runtime/ReductionTest.cpp b/flang/unittests/Optimizer/Builder/Runtime/ReductionTest.cpp new file mode 100644 --- /dev/null +++ b/flang/unittests/Optimizer/Builder/Runtime/ReductionTest.cpp @@ -0,0 +1,339 @@ +//===- ReductionTest.cpp -- Reduction 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/Reduction.h" +#include "RuntimeCallTestBase.h" +#include "gtest/gtest.h" + +TEST_F(RuntimeCallTest, genAllTest) { + auto loc = firBuilder->getUnknownLoc(); + mlir::Type seqTy = + fir::SequenceType::get(fir::SequenceType::Shape(1, 10), i32Ty); + mlir::Value undef = firBuilder->create(loc, seqTy); + mlir::Value dim = firBuilder->createIntegerConstant(loc, i32Ty, 1); + mlir::Value all = fir::runtime::genAll(*firBuilder, loc, undef, dim); + checkCallOp(all.getDefiningOp(), "_FortranAAll", 2); +} + +TEST_F(RuntimeCallTest, genAllDescriptorTest) { + auto loc = firBuilder->getUnknownLoc(); + mlir::Type seqTy = + fir::SequenceType::get(fir::SequenceType::Shape(1, 10), i32Ty); + mlir::Value result = firBuilder->create(loc, seqTy); + mlir::Value mask = firBuilder->create(loc, seqTy); + mlir::Value dim = firBuilder->createIntegerConstant(loc, i32Ty, 1); + fir::runtime::genAllDescriptor(*firBuilder, loc, result, mask, dim); + checkCallOpFromResultBox(result, "_FortranAAllDim", 3); +} + +TEST_F(RuntimeCallTest, genAnyTest) { + auto loc = firBuilder->getUnknownLoc(); + mlir::Type seqTy = + fir::SequenceType::get(fir::SequenceType::Shape(1, 10), i32Ty); + mlir::Value undef = firBuilder->create(loc, seqTy); + mlir::Value dim = firBuilder->createIntegerConstant(loc, i32Ty, 1); + mlir::Value any = fir::runtime::genAny(*firBuilder, loc, undef, dim); + checkCallOp(any.getDefiningOp(), "_FortranAAny", 2); +} + +TEST_F(RuntimeCallTest, genAnyDescriptorTest) { + auto loc = firBuilder->getUnknownLoc(); + mlir::Type seqTy = + fir::SequenceType::get(fir::SequenceType::Shape(1, 10), i32Ty); + mlir::Value result = firBuilder->create(loc, seqTy); + mlir::Value mask = firBuilder->create(loc, seqTy); + mlir::Value dim = firBuilder->createIntegerConstant(loc, i32Ty, 1); + fir::runtime::genAnyDescriptor(*firBuilder, loc, result, mask, dim); + checkCallOpFromResultBox(result, "_FortranAAnyDim", 3); +} + +TEST_F(RuntimeCallTest, genCountTest) { + auto loc = firBuilder->getUnknownLoc(); + mlir::Type seqTy = + fir::SequenceType::get(fir::SequenceType::Shape(1, 10), i32Ty); + mlir::Value undef = firBuilder->create(loc, seqTy); + mlir::Value dim = firBuilder->createIntegerConstant(loc, i32Ty, 1); + mlir::Value count = fir::runtime::genCount(*firBuilder, loc, undef, dim); + checkCallOp(count.getDefiningOp(), "_FortranACount", 2); +} + +TEST_F(RuntimeCallTest, genCountDimTest) { + auto loc = firBuilder->getUnknownLoc(); + mlir::Type seqTy = + fir::SequenceType::get(fir::SequenceType::Shape(1, 10), i32Ty); + mlir::Value result = firBuilder->create(loc, seqTy); + mlir::Value mask = firBuilder->create(loc, seqTy); + mlir::Value dim = firBuilder->createIntegerConstant(loc, i32Ty, 1); + mlir::Value kind = firBuilder->createIntegerConstant(loc, i32Ty, 1); + fir::runtime::genCountDim(*firBuilder, loc, result, mask, dim, kind); + checkCallOpFromResultBox(result, "_FortranACountDim", 4); +} + +void testGenMaxVal( + fir::FirOpBuilder &builder, mlir::Type eleTy, llvm::StringRef fctName) { + auto loc = builder.getUnknownLoc(); + mlir::Type seqTy = + fir::SequenceType::get(fir::SequenceType::Shape(1, 10), eleTy); + mlir::Type refSeqTy = fir::ReferenceType::get(seqTy); + mlir::Value undef = builder.create(loc, refSeqTy); + mlir::Value mask = builder.create(loc, seqTy); + mlir::Value max = fir::runtime::genMaxval(builder, loc, undef, mask); + checkCallOp(max.getDefiningOp(), fctName, 3); +} + +TEST_F(RuntimeCallTest, genMaxValTest) { + testGenMaxVal(*firBuilder, f32Ty, "_FortranAMaxvalReal4"); + testGenMaxVal(*firBuilder, f64Ty, "_FortranAMaxvalReal8"); + testGenMaxVal(*firBuilder, f80Ty, "_FortranAMaxvalReal10"); + testGenMaxVal(*firBuilder, f128Ty, "_FortranAMaxvalReal16"); + + testGenMaxVal(*firBuilder, i8Ty, "_FortranAMaxvalInteger1"); + testGenMaxVal(*firBuilder, i16Ty, "_FortranAMaxvalInteger2"); + testGenMaxVal(*firBuilder, i32Ty, "_FortranAMaxvalInteger4"); + testGenMaxVal(*firBuilder, i64Ty, "_FortranAMaxvalInteger8"); + testGenMaxVal(*firBuilder, i128Ty, "_FortranAMaxvalInteger16"); +} + +void testGenMinVal( + fir::FirOpBuilder &builder, mlir::Type eleTy, llvm::StringRef fctName) { + auto loc = builder.getUnknownLoc(); + mlir::Type seqTy = + fir::SequenceType::get(fir::SequenceType::Shape(1, 10), eleTy); + mlir::Type refSeqTy = fir::ReferenceType::get(seqTy); + mlir::Value undef = builder.create(loc, refSeqTy); + mlir::Value mask = builder.create(loc, seqTy); + mlir::Value min = fir::runtime::genMinval(builder, loc, undef, mask); + checkCallOp(min.getDefiningOp(), fctName, 3); +} + +TEST_F(RuntimeCallTest, genMinValTest) { + testGenMinVal(*firBuilder, f32Ty, "_FortranAMinvalReal4"); + testGenMinVal(*firBuilder, f64Ty, "_FortranAMinvalReal8"); + testGenMinVal(*firBuilder, f80Ty, "_FortranAMinvalReal10"); + testGenMinVal(*firBuilder, f128Ty, "_FortranAMinvalReal16"); + + testGenMinVal(*firBuilder, i8Ty, "_FortranAMinvalInteger1"); + testGenMinVal(*firBuilder, i16Ty, "_FortranAMinvalInteger2"); + testGenMinVal(*firBuilder, i32Ty, "_FortranAMinvalInteger4"); + testGenMinVal(*firBuilder, i64Ty, "_FortranAMinvalInteger8"); + testGenMinVal(*firBuilder, i128Ty, "_FortranAMinvalInteger16"); +} + +void testGenSum( + fir::FirOpBuilder &builder, mlir::Type eleTy, llvm::StringRef fctName) { + auto loc = builder.getUnknownLoc(); + mlir::Type seqTy = + fir::SequenceType::get(fir::SequenceType::Shape(1, 10), eleTy); + mlir::Type refSeqTy = fir::ReferenceType::get(seqTy); + mlir::Value undef = builder.create(loc, refSeqTy); + mlir::Value mask = builder.create(loc, seqTy); + mlir::Value result = builder.create(loc, seqTy); + mlir::Value sum = fir::runtime::genSum(builder, loc, undef, mask, result); + if (fir::isa_complex(eleTy)) + checkCallOpFromResultBox(result, fctName, 4); + else + checkCallOp(sum.getDefiningOp(), fctName, 3); +} + +TEST_F(RuntimeCallTest, genSumTest) { + testGenSum(*firBuilder, f32Ty, "_FortranASumReal4"); + testGenSum(*firBuilder, f64Ty, "_FortranASumReal8"); + testGenSum(*firBuilder, f80Ty, "_FortranASumReal10"); + testGenSum(*firBuilder, f128Ty, "_FortranASumReal16"); + testGenSum(*firBuilder, i8Ty, "_FortranASumInteger1"); + testGenSum(*firBuilder, i16Ty, "_FortranASumInteger2"); + testGenSum(*firBuilder, i32Ty, "_FortranASumInteger4"); + testGenSum(*firBuilder, i64Ty, "_FortranASumInteger8"); + testGenSum(*firBuilder, i128Ty, "_FortranASumInteger16"); + testGenSum(*firBuilder, c4Ty, "_FortranACppSumComplex4"); + testGenSum(*firBuilder, c8Ty, "_FortranACppSumComplex8"); + testGenSum(*firBuilder, c10Ty, "_FortranACppSumComplex10"); + testGenSum(*firBuilder, c16Ty, "_FortranACppSumComplex16"); +} + +void testGenProduct( + fir::FirOpBuilder &builder, mlir::Type eleTy, llvm::StringRef fctName) { + auto loc = builder.getUnknownLoc(); + mlir::Type seqTy = + fir::SequenceType::get(fir::SequenceType::Shape(1, 10), eleTy); + mlir::Type refSeqTy = fir::ReferenceType::get(seqTy); + mlir::Value undef = builder.create(loc, refSeqTy); + mlir::Value mask = builder.create(loc, seqTy); + mlir::Value result = builder.create(loc, seqTy); + mlir::Value prod = + fir::runtime::genProduct(builder, loc, undef, mask, result); + if (fir::isa_complex(eleTy)) + checkCallOpFromResultBox(result, fctName, 4); + else + checkCallOp(prod.getDefiningOp(), fctName, 3); +} + +TEST_F(RuntimeCallTest, genProduct) { + testGenProduct(*firBuilder, f32Ty, "_FortranAProductReal4"); + testGenProduct(*firBuilder, f64Ty, "_FortranAProductReal8"); + testGenProduct(*firBuilder, f80Ty, "_FortranAProductReal10"); + testGenProduct(*firBuilder, f128Ty, "_FortranAProductReal16"); + testGenProduct(*firBuilder, i8Ty, "_FortranAProductInteger1"); + testGenProduct(*firBuilder, i16Ty, "_FortranAProductInteger2"); + testGenProduct(*firBuilder, i32Ty, "_FortranAProductInteger4"); + testGenProduct(*firBuilder, i64Ty, "_FortranAProductInteger8"); + testGenProduct(*firBuilder, i128Ty, "_FortranAProductInteger16"); + testGenProduct(*firBuilder, c4Ty, "_FortranACppProductComplex4"); + testGenProduct(*firBuilder, c8Ty, "_FortranACppProductComplex8"); + testGenProduct(*firBuilder, c10Ty, "_FortranACppProductComplex10"); + testGenProduct(*firBuilder, c16Ty, "_FortranACppProductComplex16"); +} + +void testGenDotProduct( + fir::FirOpBuilder &builder, mlir::Type eleTy, llvm::StringRef fctName) { + auto loc = builder.getUnknownLoc(); + mlir::Type seqTy = + fir::SequenceType::get(fir::SequenceType::Shape(1, 10), eleTy); + mlir::Type refSeqTy = fir::ReferenceType::get(seqTy); + mlir::Value a = builder.create(loc, refSeqTy); + mlir::Value b = builder.create(loc, refSeqTy); + mlir::Value result = builder.create(loc, seqTy); + mlir::Value prod = fir::runtime::genDotProduct(builder, loc, a, b, result); + if (fir::isa_complex(eleTy)) + checkCallOpFromResultBox(result, fctName, 3); + else + checkCallOp(prod.getDefiningOp(), fctName, 2); +} + +TEST_F(RuntimeCallTest, genDotProduct) { + testGenDotProduct(*firBuilder, f32Ty, "_FortranADotProductReal4"); + testGenDotProduct(*firBuilder, f64Ty, "_FortranADotProductReal8"); + testGenDotProduct(*firBuilder, f80Ty, "_FortranADotProductReal10"); + testGenDotProduct(*firBuilder, f128Ty, "_FortranADotProductReal16"); + testGenDotProduct(*firBuilder, i8Ty, "_FortranADotProductInteger1"); + testGenDotProduct(*firBuilder, i16Ty, "_FortranADotProductInteger2"); + testGenDotProduct(*firBuilder, i32Ty, "_FortranADotProductInteger4"); + testGenDotProduct(*firBuilder, i64Ty, "_FortranADotProductInteger8"); + testGenDotProduct(*firBuilder, i128Ty, "_FortranADotProductInteger16"); + testGenDotProduct(*firBuilder, c4Ty, "_FortranACppDotProductComplex4"); + testGenDotProduct(*firBuilder, c8Ty, "_FortranACppDotProductComplex8"); + testGenDotProduct(*firBuilder, c10Ty, "_FortranACppDotProductComplex10"); + testGenDotProduct(*firBuilder, c16Ty, "_FortranACppDotProductComplex16"); +} + +void checkGenMxxloc(fir::FirOpBuilder &builder, + void (*genFct)(fir::FirOpBuilder &, Location, mlir::Value, mlir::Value, + mlir::Value, mlir::Value, mlir::Value), + llvm::StringRef fctName, unsigned nbArgs) { + auto loc = builder.getUnknownLoc(); + mlir::Type i32Ty = builder.getI32Type(); + mlir::Type seqTy = + fir::SequenceType::get(fir::SequenceType::Shape(1, 10), i32Ty); + mlir::Type refSeqTy = fir::ReferenceType::get(seqTy); + mlir::Value a = builder.create(loc, refSeqTy); + mlir::Value result = builder.create(loc, seqTy); + mlir::Value mask = builder.create(loc, seqTy); + mlir::Value kind = builder.createIntegerConstant(loc, i32Ty, 1); + mlir::Value back = builder.createIntegerConstant(loc, i32Ty, 1); + genFct(builder, loc, result, a, mask, kind, back); + checkCallOpFromResultBox(result, fctName, nbArgs); +} + +TEST_F(RuntimeCallTest, genMaxlocTest) { + checkGenMxxloc(*firBuilder, fir::runtime::genMaxloc, "_FortranAMaxloc", 5); +} + +TEST_F(RuntimeCallTest, genMinlocTest) { + checkGenMxxloc(*firBuilder, fir::runtime::genMinloc, "_FortranAMinloc", 5); +} + +void checkGenMxxlocDim(fir::FirOpBuilder &builder, + void (*genFct)(fir::FirOpBuilder &, Location, mlir::Value, mlir::Value, + mlir::Value, mlir::Value, mlir::Value, mlir::Value), + llvm::StringRef fctName, unsigned nbArgs) { + auto loc = builder.getUnknownLoc(); + auto i32Ty = builder.getI32Type(); + mlir::Type seqTy = + fir::SequenceType::get(fir::SequenceType::Shape(1, 10), i32Ty); + mlir::Type refSeqTy = fir::ReferenceType::get(seqTy); + mlir::Value a = builder.create(loc, refSeqTy); + mlir::Value result = builder.create(loc, seqTy); + mlir::Value mask = builder.create(loc, seqTy); + mlir::Value kind = builder.createIntegerConstant(loc, i32Ty, 1); + mlir::Value dim = builder.createIntegerConstant(loc, i32Ty, 1); + mlir::Value back = builder.createIntegerConstant(loc, i32Ty, 1); + genFct(builder, loc, result, a, dim, mask, kind, back); + checkCallOpFromResultBox(result, fctName, nbArgs); +} + +TEST_F(RuntimeCallTest, genMaxlocDimTest) { + checkGenMxxlocDim( + *firBuilder, fir::runtime::genMaxlocDim, "_FortranAMaxlocDim", 6); +} + +TEST_F(RuntimeCallTest, genMinlocDimTest) { + checkGenMxxlocDim( + *firBuilder, fir::runtime::genMinlocDim, "_FortranAMinlocDim", 6); +} + +void checkGenMxxvalChar(fir::FirOpBuilder &builder, + void (*genFct)( + fir::FirOpBuilder &, Location, mlir::Value, mlir::Value, mlir::Value), + llvm::StringRef fctName, unsigned nbArgs) { + auto loc = builder.getUnknownLoc(); + auto i32Ty = builder.getI32Type(); + mlir::Type seqTy = + fir::SequenceType::get(fir::SequenceType::Shape(1, 10), i32Ty); + mlir::Type refSeqTy = fir::ReferenceType::get(seqTy); + mlir::Value a = builder.create(loc, refSeqTy); + mlir::Value result = builder.create(loc, seqTy); + mlir::Value mask = builder.create(loc, seqTy); + genFct(builder, loc, result, a, mask); + checkCallOpFromResultBox(result, fctName, nbArgs); +} + +TEST_F(RuntimeCallTest, genMaxvalCharTest) { + checkGenMxxvalChar( + *firBuilder, fir::runtime::genMaxvalChar, "_FortranAMaxvalCharacter", 3); +} + +TEST_F(RuntimeCallTest, genMinvalCharTest) { + checkGenMxxvalChar( + *firBuilder, fir::runtime::genMinvalChar, "_FortranAMinvalCharacter", 3); +} + +void checkGen4argsDim(fir::FirOpBuilder &builder, + void (*genFct)(fir::FirOpBuilder &, Location, mlir::Value, mlir::Value, + mlir::Value, mlir::Value), + llvm::StringRef fctName, unsigned nbArgs) { + auto loc = builder.getUnknownLoc(); + auto i32Ty = builder.getI32Type(); + mlir::Type seqTy = + fir::SequenceType::get(fir::SequenceType::Shape(1, 10), i32Ty); + mlir::Type refSeqTy = fir::ReferenceType::get(seqTy); + mlir::Value a = builder.create(loc, refSeqTy); + mlir::Value result = builder.create(loc, seqTy); + mlir::Value mask = builder.create(loc, seqTy); + mlir::Value dim = builder.createIntegerConstant(loc, i32Ty, 1); + genFct(builder, loc, result, a, dim, mask); + checkCallOpFromResultBox(result, fctName, nbArgs); +} + +TEST_F(RuntimeCallTest, genMaxvalDimTest) { + checkGen4argsDim( + *firBuilder, fir::runtime::genMaxvalDim, "_FortranAMaxvalDim", 4); +} + +TEST_F(RuntimeCallTest, genMinvalDimTest) { + checkGen4argsDim( + *firBuilder, fir::runtime::genMinvalDim, "_FortranAMinvalDim", 4); +} + +TEST_F(RuntimeCallTest, genProductDimTest) { + checkGen4argsDim( + *firBuilder, fir::runtime::genProductDim, "_FortranAProductDim", 4); +} + +TEST_F(RuntimeCallTest, genSumDimTest) { + checkGen4argsDim(*firBuilder, fir::runtime::genSumDim, "_FortranASumDim", 4); +} diff --git a/flang/unittests/Optimizer/Builder/Runtime/RuntimeCallTestBase.h b/flang/unittests/Optimizer/Builder/Runtime/RuntimeCallTestBase.h new file mode 100644 --- /dev/null +++ b/flang/unittests/Optimizer/Builder/Runtime/RuntimeCallTestBase.h @@ -0,0 +1,97 @@ +//===- RuntimeCalltestBase.cpp -- Base for runtime call generation 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 +// +//===----------------------------------------------------------------------===// + +#ifndef FORTRAN_OPTIMIZER_BUILDER_RUNTIME_RUNTIMECALLTESTBASE_H +#define FORTRAN_OPTIMIZER_BUILDER_RUNTIME_RUNTIMECALLTESTBASE_H + +#include "gtest/gtest.h" +#include "flang/Optimizer/Builder/FIRBuilder.h" +#include "flang/Optimizer/Support/InitFIR.h" +#include "flang/Optimizer/Support/KindMapping.h" + +struct RuntimeCallTest : public testing::Test { +public: + void SetUp() override { + mlir::OpBuilder builder(&context); + auto loc = builder.getUnknownLoc(); + + // Set up a Module with a dummy function operation inside. + // Set the insertion point in the function entry block. + mlir::ModuleOp mod = builder.create(loc); + mlir::FuncOp func = mlir::FuncOp::create( + loc, "func1", builder.getFunctionType(llvm::None, llvm::None)); + auto *entryBlock = func.addEntryBlock(); + mod.push_back(mod); + builder.setInsertionPointToStart(entryBlock); + + fir::support::loadDialects(context); + kindMap = std::make_unique(&context); + firBuilder = std::make_unique(mod, *kindMap); + + i8Ty = firBuilder->getI8Type(); + i16Ty = firBuilder->getIntegerType(16); + i32Ty = firBuilder->getI32Type(); + i64Ty = firBuilder->getI64Type(); + i128Ty = firBuilder->getIntegerType(128); + + f32Ty = firBuilder->getF32Type(); + f64Ty = firBuilder->getF64Type(); + f80Ty = firBuilder->getF80Type(); + f128Ty = firBuilder->getF128Type(); + + c4Ty = fir::ComplexType::get(firBuilder->getContext(), 4); + c8Ty = fir::ComplexType::get(firBuilder->getContext(), 8); + c10Ty = fir::ComplexType::get(firBuilder->getContext(), 10); + c16Ty = fir::ComplexType::get(firBuilder->getContext(), 16); + } + + mlir::MLIRContext context; + std::unique_ptr kindMap; + std::unique_ptr firBuilder; + + // Commnly used type + mlir::Type i8Ty; + mlir::Type i16Ty; + mlir::Type i32Ty; + mlir::Type i64Ty; + mlir::Type i128Ty; + mlir::Type f32Ty; + mlir::Type f64Ty; + mlir::Type f80Ty; + mlir::Type f128Ty; + mlir::Type c4Ty; + mlir::Type c8Ty; + mlir::Type c10Ty; + mlir::Type c16Ty; +}; + +static void checkCallOp( + mlir::Operation *op, llvm::StringRef fctName, unsigned nbArgs) { + EXPECT_TRUE(mlir::isa(*op)); + auto callOp = mlir::dyn_cast(*op); + EXPECT_TRUE(callOp.callee().hasValue()); + mlir::SymbolRefAttr callee = *callOp.callee(); + EXPECT_EQ(fctName, callee.getRootReference().getValue()); + // sourceFile and sourceLine are added arguments. + EXPECT_EQ(nbArgs + 2, callOp.args().size()); +} + +static void checkCallOpFromResultBox( + mlir::Value result, llvm::StringRef fctName, unsigned nbArgs) { + EXPECT_TRUE(result.hasOneUse()); + for (auto &u : result.getUses()) { + if (mlir::isa(*u.getOwner())) { + checkCallOp(u.getOwner(), fctName, nbArgs); + } else { + auto convOp = mlir::dyn_cast(*u.getOwner()); + checkCallOpFromResultBox(convOp.getResult(), fctName, nbArgs); + } + } +} + +#endif // FORTRAN_OPTIMIZER_BUILDER_RUNTIME_RUNTIMECALLTESTBASE_H 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/ReductionTest.cpp FIRContextTest.cpp InternalNamesTest.cpp KindMappingTest.cpp