| //===-- Lower/CustomIntrinsicCall.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 |
| // |
| //===----------------------------------------------------------------------===// |
| // |
| // Coding style: https://mlir.llvm.org/getting_started/DeveloperGuide/ |
| // |
| //===----------------------------------------------------------------------===// |
| /// |
| /// Custom intrinsic lowering for the few intrinsic that have optional |
| /// arguments that prevents them to be handled in a more generic way in |
| /// IntrinsicCall.cpp. |
| /// The core principle is that this interface provides the intrinsic arguments |
| /// via callbacks to generate fir::ExtendedValue (instead of a list of |
| /// precomputed fir::ExtendedValue as done in the default intrinsic call |
| /// lowering). This gives more flexibility to only generate references to |
| /// dynamically optional arguments (pointers, allocatables, OPTIONAL dummies) in |
| /// a safe way. |
| //===----------------------------------------------------------------------===// |
| |
| #ifndef FORTRAN_LOWER_CUSTOMINTRINSICCALL_H |
| #define FORTRAN_LOWER_CUSTOMINTRINSICCALL_H |
| |
| #include "flang/Lower/AbstractConverter.h" |
| #include "flang/Optimizer/Builder/IntrinsicCall.h" |
| #include <functional> |
| #include <optional> |
| |
| namespace Fortran { |
| |
| namespace evaluate { |
| class ProcedureRef; |
| struct SpecificIntrinsic; |
| } // namespace evaluate |
| |
| namespace lower { |
| |
| /// Does the call \p procRef to \p intrinsic need to be handle via this custom |
| /// framework due to optional arguments. Otherwise, the tools from |
| /// IntrinsicCall.cpp should be used directly. |
| bool intrinsicRequiresCustomOptionalHandling( |
| const Fortran::evaluate::ProcedureRef &procRef, |
| const Fortran::evaluate::SpecificIntrinsic &intrinsic, |
| AbstractConverter &converter); |
| |
| /// Type of callback to be provided to prepare the arguments fetching from an |
| /// actual argument expression. |
| using OperandPrepare = std::function<void(const Fortran::lower::SomeExpr &)>; |
| using OperandPrepareAs = std::function<void(const Fortran::lower::SomeExpr &, |
| fir::LowerIntrinsicArgAs)>; |
| |
| /// Type of the callback to inquire about an argument presence, once the call |
| /// preparation was done. An absent optional means the argument is statically |
| /// present. An mlir::Value means the presence must be checked at runtime, and |
| /// that the value contains the "is present" boolean value. |
| using OperandPresent = std::function<std::optional<mlir::Value>(std::size_t)>; |
| |
| /// Type of the callback to generate an argument reference after the call |
| /// preparation was done. For optional arguments, the utility guarantees |
| /// these callbacks will only be called in regions where the presence was |
| /// verified. This means the getter callback can dereference the argument |
| /// without any special care. |
| /// For elemental intrinsics, the getter must provide the current iteration |
| /// element value. If the boolean argument is true, the callback must load the |
| /// argument before returning it. |
| using OperandGetter = std::function<fir::ExtendedValue(std::size_t, bool)>; |
| |
| /// Given a callback \p prepareOptionalArgument to prepare optional |
| /// arguments and a callback \p prepareOtherArgument to prepare non-optional |
| /// arguments prepare the intrinsic arguments calls. |
| /// It is up to the caller to decide what argument preparation means, |
| /// the only contract is that it should later allow the caller to provide |
| /// callbacks to generate argument reference given an argument index without |
| /// any further knowledge of the argument. The function simply visits |
| /// the actual arguments, deciding which ones are dynamically optional, |
| /// and calling the callbacks accordingly in argument order. |
| void prepareCustomIntrinsicArgument( |
| const Fortran::evaluate::ProcedureRef &procRef, |
| const Fortran::evaluate::SpecificIntrinsic &intrinsic, |
| std::optional<mlir::Type> retTy, |
| const OperandPrepare &prepareOptionalArgument, |
| const OperandPrepareAs &prepareOtherArgument, AbstractConverter &converter); |
| |
| /// Given a callback \p getOperand to generate a reference to the i-th argument, |
| /// and a callback \p isPresentCheck to test if an argument is present, this |
| /// function lowers the intrinsic calls to \p name whose argument were |
| /// previously prepared with prepareCustomIntrinsicArgument. The elemental |
| /// aspects must be taken into account by the caller (i.e, the function should |
| /// be called during the loop nest generation for elemental intrinsics. It will |
| /// not generate any implicit loop nest on its own). |
| fir::ExtendedValue |
| lowerCustomIntrinsic(fir::FirOpBuilder &builder, mlir::Location loc, |
| llvm::StringRef name, std::optional<mlir::Type> retTy, |
| const OperandPresent &isPresentCheck, |
| const OperandGetter &getOperand, std::size_t numOperands, |
| Fortran::lower::StatementContext &stmtCtx); |
| |
| /// DEPRICATED: NEW CODE SHOULD USE THE VERSION OF genIntrinsicCall WITHOUT A |
| /// StatementContext, DECLARED IN IntrinsicCall.h |
| /// Generate the FIR+MLIR operations for the generic intrinsic \p name |
| /// with argument \p args and expected result type \p resultType. |
| /// Returned fir::ExtendedValue is the returned Fortran intrinsic value. |
| fir::ExtendedValue |
| genIntrinsicCall(fir::FirOpBuilder &builder, mlir::Location loc, |
| llvm::StringRef name, std::optional<mlir::Type> resultType, |
| llvm::ArrayRef<fir::ExtendedValue> args, |
| StatementContext &stmtCtx, |
| Fortran::lower::AbstractConverter *converter = nullptr); |
| |
| } // namespace lower |
| } // namespace Fortran |
| |
| #endif // FORTRAN_LOWER_CUSTOMINTRINSICCALL_H |