diff --git a/flang/include/flang/Optimizer/Builder/IntrinsicCall.h b/flang/include/flang/Optimizer/Builder/IntrinsicCall.h --- a/flang/include/flang/Optimizer/Builder/IntrinsicCall.h +++ b/flang/include/flang/Optimizer/Builder/IntrinsicCall.h @@ -10,8 +10,14 @@ #define FORTRAN_LOWER_INTRINSICCALL_H #include "flang/Optimizer/Builder/FIRBuilder.h" +#include "flang/Optimizer/Builder/Runtime/Character.h" +#include "flang/Optimizer/Builder/Runtime/Numeric.h" #include "flang/Optimizer/Builder/Runtime/RTBuilder.h" +#include "flang/Runtime/entry-names.h" #include "flang/Runtime/iostat.h" +#include "mlir/Dialect/Complex/IR/Complex.h" +#include "mlir/Dialect/LLVMIR/LLVMDialect.h" +#include "mlir/Dialect/Math/IR/Math.h" #include namespace fir { @@ -104,6 +110,11 @@ bool handleDynamicOptional; }; +constexpr auto asValue = fir::LowerIntrinsicArgAs::Value; +constexpr auto asAddr = fir::LowerIntrinsicArgAs::Addr; +constexpr auto asBox = fir::LowerIntrinsicArgAs::Box; +constexpr auto asInquired = fir::LowerIntrinsicArgAs::Inquired; + /// Opaque class defining the argument lowering rules for all the argument of /// an intrinsic. struct IntrinsicArgumentLoweringRules; @@ -310,10 +321,6 @@ /// is ignored because this is already reflected in the result type. mlir::Value genConversion(mlir::Type, llvm::ArrayRef); - // PPC intrinsic handlers. - template - void genMtfsf(llvm::ArrayRef); - /// In the template helper below: /// - "FN func" is a callback to generate the related intrinsic runtime call. /// - "FD funcDim" is a callback to generate the "dim" runtime call. @@ -550,6 +557,29 @@ return mlir::FunctionType::get(context, argTypes, {resType}); } +mlir::Value genLibCall(fir::FirOpBuilder &builder, mlir::Location loc, + llvm::StringRef libFuncName, + mlir::FunctionType libFuncType, + llvm::ArrayRef args); + +template +mlir::Value genMathOp(fir::FirOpBuilder &builder, mlir::Location loc, + llvm::StringRef mathLibFuncName, + mlir::FunctionType mathLibFuncType, + llvm::ArrayRef args); + +template +mlir::Value genComplexMathOp(fir::FirOpBuilder &builder, mlir::Location loc, + llvm::StringRef mathLibFuncName, + mlir::FunctionType mathLibFuncType, + llvm::ArrayRef args); + +mlir::Value genLibSplitComplexArgsCall(fir::FirOpBuilder &builder, + mlir::Location loc, + llvm::StringRef libFuncName, + mlir::FunctionType libFuncType, + llvm::ArrayRef args); + /// Return argument lowering rules for an intrinsic. /// Returns a nullptr if all the intrinsic arguments should be lowered by value. const IntrinsicArgumentLoweringRules * diff --git a/flang/include/flang/Optimizer/Builder/PPCIntrinsicCall.h b/flang/include/flang/Optimizer/Builder/PPCIntrinsicCall.h new file mode 100644 --- /dev/null +++ b/flang/include/flang/Optimizer/Builder/PPCIntrinsicCall.h @@ -0,0 +1,38 @@ +//==-- Builder/PPCIntrinsicCall.h - lowering of PowerPC intrinsics -*-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_LOWER_PPCINTRINSICCALL_H +#define FORTRAN_LOWER_PPCINTRINSICCALL_H + +#include "flang/Common/static-multimap-view.h" +#include "flang/Optimizer/Builder/IntrinsicCall.h" +#include "mlir/Dialect/Math/IR/Math.h" + +namespace fir { + +struct PPCIntrinsicLibrary : IntrinsicLibrary { + + // Constructors. + explicit PPCIntrinsicLibrary(fir::FirOpBuilder &builder, mlir::Location loc) + : IntrinsicLibrary(builder, loc) {} + PPCIntrinsicLibrary() = delete; + PPCIntrinsicLibrary(const PPCIntrinsicLibrary &) = delete; + + // PPC intrinsic handlers. + template + void genMtfsf(llvm::ArrayRef); +}; + +const IntrinsicHandler *findPPCIntrinsicHandler(llvm::StringRef name); + +std::pair +checkPPCMathOperationsRange(llvm::StringRef name); + +} // namespace fir + +#endif // FORTRAN_LOWER_PPCINTRINSICCALL_H diff --git a/flang/lib/Optimizer/Builder/CMakeLists.txt b/flang/lib/Optimizer/Builder/CMakeLists.txt --- a/flang/lib/Optimizer/Builder/CMakeLists.txt +++ b/flang/lib/Optimizer/Builder/CMakeLists.txt @@ -10,6 +10,7 @@ IntrinsicCall.cpp LowLevelIntrinsics.cpp MutableBox.cpp + PPCIntrinsicCall.cpp Runtime/Allocatable.cpp Runtime/ArrayConstructor.cpp Runtime/Assign.cpp diff --git a/flang/lib/Optimizer/Builder/IntrinsicCall.cpp b/flang/lib/Optimizer/Builder/IntrinsicCall.cpp --- a/flang/lib/Optimizer/Builder/IntrinsicCall.cpp +++ b/flang/lib/Optimizer/Builder/IntrinsicCall.cpp @@ -20,6 +20,7 @@ #include "flang/Optimizer/Builder/Complex.h" #include "flang/Optimizer/Builder/FIRBuilder.h" #include "flang/Optimizer/Builder/MutableBox.h" +#include "flang/Optimizer/Builder/PPCIntrinsicCall.h" #include "flang/Optimizer/Builder/Runtime/Allocatable.h" #include "flang/Optimizer/Builder/Runtime/Character.h" #include "flang/Optimizer/Builder/Runtime/Command.h" @@ -88,10 +89,6 @@ return !isStaticallyAbsent(exv); } -constexpr auto asValue = fir::LowerIntrinsicArgAs::Value; -constexpr auto asAddr = fir::LowerIntrinsicArgAs::Addr; -constexpr auto asBox = fir::LowerIntrinsicArgAs::Box; -constexpr auto asInquired = fir::LowerIntrinsicArgAs::Inquired; using I = IntrinsicLibrary; /// Flag to indicate that an intrinsic argument has to be handled as @@ -521,18 +518,6 @@ /*isElemental=*/true}, }; -// PPC specific intrinsic handlers. -static constexpr IntrinsicHandler ppcHandlers[]{ - {"__ppc_mtfsf", - &I::genMtfsf, - {{{"mask", asValue}, {"r", asValue}}}, - /*isElemental=*/false}, - {"__ppc_mtfsfi", - &I::genMtfsf, - {{{"bf", asValue}, {"i", asValue}}}, - /*isElemental=*/false}, -}; - static const IntrinsicHandler *findIntrinsicHandler(llvm::StringRef name) { auto compare = [](const IntrinsicHandler &handler, llvm::StringRef name) { return name.compare(handler.name) > 0; @@ -542,15 +527,6 @@ : nullptr; } -static const IntrinsicHandler *findPPCIntrinsicHandler(llvm::StringRef name) { - auto compare = [](const IntrinsicHandler &ppcHandler, llvm::StringRef name) { - return name.compare(ppcHandler.name) > 0; - }; - auto result = llvm::lower_bound(ppcHandlers, name, compare); - return result != std::end(ppcHandlers) && result->name == name ? result - : nullptr; -} - /// To make fir output more readable for debug, one can outline all intrinsic /// implementation in wrappers (overrides the IntrinsicHandler::outline flag). static llvm::cl::opt outlineAllIntrinsics( @@ -580,10 +556,10 @@ "dialect to lower complex operations"), llvm::cl::init(false)); -static mlir::Value genLibCall(fir::FirOpBuilder &builder, mlir::Location loc, - llvm::StringRef libFuncName, - mlir::FunctionType libFuncType, - llvm::ArrayRef args) { +mlir::Value genLibCall(fir::FirOpBuilder &builder, mlir::Location loc, + llvm::StringRef libFuncName, + mlir::FunctionType libFuncType, + llvm::ArrayRef args) { LLVM_DEBUG(llvm::dbgs() << "Generating '" << libFuncName << "' call with type "; libFuncType.dump(); llvm::dbgs() << "\n"); @@ -639,9 +615,11 @@ return libCall.getResult(0); } -static mlir::Value genLibSplitComplexArgsCall( - fir::FirOpBuilder &builder, mlir::Location loc, llvm::StringRef libFuncName, - mlir::FunctionType libFuncType, llvm::ArrayRef args) { +mlir::Value genLibSplitComplexArgsCall(fir::FirOpBuilder &builder, + mlir::Location loc, + llvm::StringRef libFuncName, + mlir::FunctionType libFuncType, + llvm::ArrayRef args) { assert(args.size() == 2 && "Incorrect #args to genLibSplitComplexArgsCall"); auto getSplitComplexArgsType = [&builder, &args]() -> mlir::FunctionType { @@ -688,10 +666,10 @@ } template -static mlir::Value genMathOp(fir::FirOpBuilder &builder, mlir::Location loc, - llvm::StringRef mathLibFuncName, - mlir::FunctionType mathLibFuncType, - llvm::ArrayRef args) { +mlir::Value genMathOp(fir::FirOpBuilder &builder, mlir::Location loc, + llvm::StringRef mathLibFuncName, + mlir::FunctionType mathLibFuncType, + llvm::ArrayRef args) { // TODO: we have to annotate the math operations with flags // that will allow to define FP accuracy/exception // behavior per operation, so that after early multi-module @@ -730,11 +708,10 @@ } template -static mlir::Value genComplexMathOp(fir::FirOpBuilder &builder, - mlir::Location loc, - llvm::StringRef mathLibFuncName, - mlir::FunctionType mathLibFuncType, - llvm::ArrayRef args) { +mlir::Value genComplexMathOp(fir::FirOpBuilder &builder, mlir::Location loc, + llvm::StringRef mathLibFuncName, + mlir::FunctionType mathLibFuncType, + llvm::ArrayRef args) { mlir::Value result; if (disableMlirComplex || (mathRuntimeVersion == preciseVersion && !mathLibFuncName.empty())) { @@ -1037,64 +1014,6 @@ genComplexMathOp}, }; -static constexpr MathOperation ppcMathOperations[] = { - // fcfi is just another name for fcfid, there is no llvm.ppc.fcfi. - {"__ppc_fcfi", "llvm.ppc.fcfid", genFuncType, Ty::Real<8>>, - genLibCall}, - {"__ppc_fcfid", "llvm.ppc.fcfid", genFuncType, Ty::Real<8>>, - genLibCall}, - {"__ppc_fcfud", "llvm.ppc.fcfud", genFuncType, Ty::Real<8>>, - genLibCall}, - {"__ppc_fctid", "llvm.ppc.fctid", genFuncType, Ty::Real<8>>, - genLibCall}, - {"__ppc_fctidz", "llvm.ppc.fctidz", genFuncType, Ty::Real<8>>, - genLibCall}, - {"__ppc_fctiw", "llvm.ppc.fctiw", genFuncType, Ty::Real<8>>, - genLibCall}, - {"__ppc_fctiwz", "llvm.ppc.fctiwz", genFuncType, Ty::Real<8>>, - genLibCall}, - {"__ppc_fctudz", "llvm.ppc.fctudz", genFuncType, Ty::Real<8>>, - genLibCall}, - {"__ppc_fctuwz", "llvm.ppc.fctuwz", genFuncType, Ty::Real<8>>, - genLibCall}, - {"__ppc_fmadd", "llvm.fma.f32", - genFuncType, Ty::Real<4>, Ty::Real<4>, Ty::Real<4>>, - genMathOp}, - {"__ppc_fmadd", "llvm.fma.f64", - genFuncType, Ty::Real<8>, Ty::Real<8>, Ty::Real<8>>, - genMathOp}, - {"__ppc_fmsub", "llvm.ppc.fmsubs", - genFuncType, Ty::Real<4>, Ty::Real<4>, Ty::Real<4>>, - genLibCall}, - {"__ppc_fmsub", "llvm.ppc.fmsub", - genFuncType, Ty::Real<8>, Ty::Real<8>, Ty::Real<8>>, - genLibCall}, - {"__ppc_fnabs", "llvm.ppc.fnabss", genFuncType, Ty::Real<4>>, - genLibCall}, - {"__ppc_fnabs", "llvm.ppc.fnabs", genFuncType, Ty::Real<8>>, - genLibCall}, - {"__ppc_fnmadd", "llvm.ppc.fnmadds", - genFuncType, Ty::Real<4>, Ty::Real<4>, Ty::Real<4>>, - genLibCall}, - {"__ppc_fnmadd", "llvm.ppc.fnmadd", - genFuncType, Ty::Real<8>, Ty::Real<8>, Ty::Real<8>>, - genLibCall}, - {"__ppc_fnmsub", "llvm.ppc.fnmsub.f32", - genFuncType, Ty::Real<4>, Ty::Real<4>, Ty::Real<4>>, - genLibCall}, - {"__ppc_fnmsub", "llvm.ppc.fnmsub.f64", - genFuncType, Ty::Real<8>, Ty::Real<8>, Ty::Real<8>>, - genLibCall}, - {"__ppc_fre", "llvm.ppc.fre", genFuncType, Ty::Real<8>>, - genLibCall}, - {"__ppc_fres", "llvm.ppc.fres", genFuncType, Ty::Real<4>>, - genLibCall}, - {"__ppc_frsqrte", "llvm.ppc.frsqrte", genFuncType, Ty::Real<8>>, - genLibCall}, - {"__ppc_frsqrtes", "llvm.ppc.frsqrtes", - genFuncType, Ty::Real<4>>, genLibCall}, -}; - // This helper class computes a "distance" between two function types. // The distance measures how many narrowing conversions of actual arguments // and result of "from" must be made in order to use "to" instead of "from". @@ -1239,10 +1158,6 @@ static constexpr RtMap mathOps(mathOperations); static_assert(mathOps.Verify() && "map must be sorted"); -// PPC -static constexpr RtMap ppcMathOps(ppcMathOperations); -static_assert(ppcMathOps.Verify() && "map must be sorted"); - /// Look for a MathOperation entry specifying how to lower a mathematical /// operation defined by \p name with its result' and operands' types /// specified in the form of a FunctionType \p funcType. @@ -1264,7 +1179,7 @@ // Search ppcMathOps only if targetting PowerPC arch if (fir::getTargetTriple(mod).isPPC() && range.first == range.second) { - range = ppcMathOps.equal_range(name); + range = checkPPCMathOperationsRange(name); } for (auto iter = range.first; iter != range.second && iter; ++iter) { const auto &impl = *iter; @@ -5212,33 +5127,6 @@ return result; } -//===----------------------------------------------------------------------===// -// PowerPC specific intrinsic handlers. -//===----------------------------------------------------------------------===// -template -void IntrinsicLibrary::genMtfsf(llvm::ArrayRef args) { - assert(args.size() == 2); - llvm::SmallVector scalarArgs; - for (const fir::ExtendedValue &arg : args) - if (arg.getUnboxed()) - scalarArgs.emplace_back(fir::getBase(arg)); - else - mlir::emitError(loc, "nonscalar intrinsic argument"); - - mlir::FunctionType libFuncType; - mlir::func::FuncOp funcOp; - if (isImm) { - libFuncType = genFuncType, Ty::Integer<4>>( - builder.getContext(), builder); - funcOp = builder.addNamedFunction(loc, "llvm.ppc.mtfsfi", libFuncType); - } else { - libFuncType = genFuncType, Ty::Real<8>>( - builder.getContext(), builder); - funcOp = builder.addNamedFunction(loc, "llvm.ppc.mtfsf", libFuncType); - } - builder.create(loc, funcOp, scalarArgs); -} - //===----------------------------------------------------------------------===// // Argument lowering rules interface for intrinsic or intrinsic module // procedure. diff --git a/flang/lib/Optimizer/Builder/PPCIntrinsicCall.cpp b/flang/lib/Optimizer/Builder/PPCIntrinsicCall.cpp new file mode 100644 --- /dev/null +++ b/flang/lib/Optimizer/Builder/PPCIntrinsicCall.cpp @@ -0,0 +1,140 @@ +//===-- PPCIntrinsicCall.cpp ----------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// +// +// Helper routines for constructing the FIR dialect of MLIR for PowerPC +// intrinsics. Extensive use of MLIR interfaces and MLIR's coding style +// (https://mlir.llvm.org/getting_started/DeveloperGuide/) is used in this +// module. +// +//===----------------------------------------------------------------------===// + +#include "flang/Optimizer/Builder/PPCIntrinsicCall.h" +#include "flang/Optimizer/Builder/FIRBuilder.h" +#include "flang/Optimizer/Builder/IntrinsicCall.h" +#include "flang/Optimizer/Builder/MutableBox.h" + +namespace fir { + +using PI = PPCIntrinsicLibrary; + +// PPC specific intrinsic handlers. +static constexpr IntrinsicHandler ppcHandlers[]{ + {"__ppc_mtfsf", + static_cast(&PI::genMtfsf), + {{{"mask", asValue}, {"r", asValue}}}, + /*isElemental=*/false}, + {"__ppc_mtfsfi", + static_cast(&PI::genMtfsf), + {{{"bf", asValue}, {"i", asValue}}}, + /*isElemental=*/false}, +}; + +static constexpr MathOperation ppcMathOperations[] = { + // fcfi is just another name for fcfid, there is no llvm.ppc.fcfi. + {"__ppc_fcfi", "llvm.ppc.fcfid", genFuncType, Ty::Real<8>>, + genLibCall}, + {"__ppc_fcfid", "llvm.ppc.fcfid", genFuncType, Ty::Real<8>>, + genLibCall}, + {"__ppc_fcfud", "llvm.ppc.fcfud", genFuncType, Ty::Real<8>>, + genLibCall}, + {"__ppc_fctid", "llvm.ppc.fctid", genFuncType, Ty::Real<8>>, + genLibCall}, + {"__ppc_fctidz", "llvm.ppc.fctidz", genFuncType, Ty::Real<8>>, + genLibCall}, + {"__ppc_fctiw", "llvm.ppc.fctiw", genFuncType, Ty::Real<8>>, + genLibCall}, + {"__ppc_fctiwz", "llvm.ppc.fctiwz", genFuncType, Ty::Real<8>>, + genLibCall}, + {"__ppc_fctudz", "llvm.ppc.fctudz", genFuncType, Ty::Real<8>>, + genLibCall}, + {"__ppc_fctuwz", "llvm.ppc.fctuwz", genFuncType, Ty::Real<8>>, + genLibCall}, + {"__ppc_fmadd", "llvm.fma.f32", + genFuncType, Ty::Real<4>, Ty::Real<4>, Ty::Real<4>>, + genMathOp}, + {"__ppc_fmadd", "llvm.fma.f64", + genFuncType, Ty::Real<8>, Ty::Real<8>, Ty::Real<8>>, + genMathOp}, + {"__ppc_fmsub", "llvm.ppc.fmsubs", + genFuncType, Ty::Real<4>, Ty::Real<4>, Ty::Real<4>>, + genLibCall}, + {"__ppc_fmsub", "llvm.ppc.fmsub", + genFuncType, Ty::Real<8>, Ty::Real<8>, Ty::Real<8>>, + genLibCall}, + {"__ppc_fnabs", "llvm.ppc.fnabss", genFuncType, Ty::Real<4>>, + genLibCall}, + {"__ppc_fnabs", "llvm.ppc.fnabs", genFuncType, Ty::Real<8>>, + genLibCall}, + {"__ppc_fnmadd", "llvm.ppc.fnmadds", + genFuncType, Ty::Real<4>, Ty::Real<4>, Ty::Real<4>>, + genLibCall}, + {"__ppc_fnmadd", "llvm.ppc.fnmadd", + genFuncType, Ty::Real<8>, Ty::Real<8>, Ty::Real<8>>, + genLibCall}, + {"__ppc_fnmsub", "llvm.ppc.fnmsub.f32", + genFuncType, Ty::Real<4>, Ty::Real<4>, Ty::Real<4>>, + genLibCall}, + {"__ppc_fnmsub", "llvm.ppc.fnmsub.f64", + genFuncType, Ty::Real<8>, Ty::Real<8>, Ty::Real<8>>, + genLibCall}, + {"__ppc_fre", "llvm.ppc.fre", genFuncType, Ty::Real<8>>, + genLibCall}, + {"__ppc_fres", "llvm.ppc.fres", genFuncType, Ty::Real<4>>, + genLibCall}, + {"__ppc_frsqrte", "llvm.ppc.frsqrte", genFuncType, Ty::Real<8>>, + genLibCall}, + {"__ppc_frsqrtes", "llvm.ppc.frsqrtes", + genFuncType, Ty::Real<4>>, genLibCall}, +}; + +const IntrinsicHandler *findPPCIntrinsicHandler(llvm::StringRef name) { + auto compare = [](const IntrinsicHandler &ppcHandler, llvm::StringRef name) { + return name.compare(ppcHandler.name) > 0; + }; + auto result = llvm::lower_bound(ppcHandlers, name, compare); + return result != std::end(ppcHandlers) && result->name == name ? result + : nullptr; +} + +using RtMap = Fortran::common::StaticMultimapView; +static constexpr RtMap ppcMathOps(ppcMathOperations); +static_assert(ppcMathOps.Verify() && "map must be sorted"); + +std::pair +checkPPCMathOperationsRange(llvm::StringRef name) { + return ppcMathOps.equal_range(name); +} + +//===----------------------------------------------------------------------===// +// PowerPC specific intrinsic handlers. +//===----------------------------------------------------------------------===// +template +void PPCIntrinsicLibrary::genMtfsf(llvm::ArrayRef args) { + assert(args.size() == 2); + llvm::SmallVector scalarArgs; + for (const fir::ExtendedValue &arg : args) + if (arg.getUnboxed()) + scalarArgs.emplace_back(fir::getBase(arg)); + else + mlir::emitError(loc, "nonscalar intrinsic argument"); + + mlir::FunctionType libFuncType; + mlir::func::FuncOp funcOp; + if (isImm) { + libFuncType = genFuncType, Ty::Integer<4>>( + builder.getContext(), builder); + funcOp = builder.addNamedFunction(loc, "llvm.ppc.mtfsfi", libFuncType); + } else { + libFuncType = genFuncType, Ty::Real<8>>( + builder.getContext(), builder); + funcOp = builder.addNamedFunction(loc, "llvm.ppc.mtfsf", libFuncType); + } + builder.create(loc, funcOp, scalarArgs); +} + +} // namespace fir