1 //===-- Lower/CustomIntrinsicCall.h -----------------------------*- C++ -*-===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 // Coding style: https://mlir.llvm.org/getting_started/DeveloperGuide/ 10 // 11 //===----------------------------------------------------------------------===// 12 /// 13 /// Custom intrinsic lowering for the few intrinsic that have optional 14 /// arguments that prevents them to be handled in a more generic way in 15 /// IntrinsicCall.cpp. 16 /// The core principle is that this interface provides the intrinsic arguments 17 /// via callbacks to generate fir::ExtendedValue (instead of a list of 18 /// precomputed fir::ExtendedValue as done in the default intrinsic call 19 /// lowering). This gives more flexibility to only generate references to 20 /// dynamically optional arguments (pointers, allocatables, OPTIONAL dummies) in 21 /// a safe way. 22 //===----------------------------------------------------------------------===// 23 24 #ifndef FORTRAN_LOWER_CUSTOMINTRINSICCALL_H 25 #define FORTRAN_LOWER_CUSTOMINTRINSICCALL_H 26 27 #include "flang/Lower/AbstractConverter.h" 28 #include "flang/Optimizer/Builder/IntrinsicCall.h" 29 #include <functional> 30 #include <optional> 31 32 namespace Fortran { 33 34 namespace evaluate { 35 class ProcedureRef; 36 struct SpecificIntrinsic; 37 } // namespace evaluate 38 39 namespace lower { 40 41 /// Does the call \p procRef to \p intrinsic need to be handle via this custom 42 /// framework due to optional arguments. Otherwise, the tools from 43 /// IntrinsicCall.cpp should be used directly. 44 bool intrinsicRequiresCustomOptionalHandling( 45 const Fortran::evaluate::ProcedureRef &procRef, 46 const Fortran::evaluate::SpecificIntrinsic &intrinsic, 47 AbstractConverter &converter); 48 49 /// Type of callback to be provided to prepare the arguments fetching from an 50 /// actual argument expression. 51 using OperandPrepare = std::function<void(const Fortran::lower::SomeExpr &)>; 52 using OperandPrepareAs = std::function<void(const Fortran::lower::SomeExpr &, 53 fir::LowerIntrinsicArgAs)>; 54 55 /// Type of the callback to inquire about an argument presence, once the call 56 /// preparation was done. An absent optional means the argument is statically 57 /// present. An mlir::Value means the presence must be checked at runtime, and 58 /// that the value contains the "is present" boolean value. 59 using OperandPresent = std::function<std::optional<mlir::Value>(std::size_t)>; 60 61 /// Type of the callback to generate an argument reference after the call 62 /// preparation was done. For optional arguments, the utility guarantees 63 /// these callbacks will only be called in regions where the presence was 64 /// verified. This means the getter callback can dereference the argument 65 /// without any special care. 66 /// For elemental intrinsics, the getter must provide the current iteration 67 /// element value. If the boolean argument is true, the callback must load the 68 /// argument before returning it. 69 using OperandGetter = std::function<fir::ExtendedValue(std::size_t, bool)>; 70 71 /// Given a callback \p prepareOptionalArgument to prepare optional 72 /// arguments and a callback \p prepareOtherArgument to prepare non-optional 73 /// arguments prepare the intrinsic arguments calls. 74 /// It is up to the caller to decide what argument preparation means, 75 /// the only contract is that it should later allow the caller to provide 76 /// callbacks to generate argument reference given an argument index without 77 /// any further knowledge of the argument. The function simply visits 78 /// the actual arguments, deciding which ones are dynamically optional, 79 /// and calling the callbacks accordingly in argument order. 80 void prepareCustomIntrinsicArgument( 81 const Fortran::evaluate::ProcedureRef &procRef, 82 const Fortran::evaluate::SpecificIntrinsic &intrinsic, 83 std::optional<mlir::Type> retTy, 84 const OperandPrepare &prepareOptionalArgument, 85 const OperandPrepareAs &prepareOtherArgument, AbstractConverter &converter); 86 87 /// Given a callback \p getOperand to generate a reference to the i-th argument, 88 /// and a callback \p isPresentCheck to test if an argument is present, this 89 /// function lowers the intrinsic calls to \p name whose argument were 90 /// previously prepared with prepareCustomIntrinsicArgument. The elemental 91 /// aspects must be taken into account by the caller (i.e, the function should 92 /// be called during the loop nest generation for elemental intrinsics. It will 93 /// not generate any implicit loop nest on its own). 94 fir::ExtendedValue 95 lowerCustomIntrinsic(fir::FirOpBuilder &builder, mlir::Location loc, 96 llvm::StringRef name, std::optional<mlir::Type> retTy, 97 const OperandPresent &isPresentCheck, 98 const OperandGetter &getOperand, std::size_t numOperands, 99 Fortran::lower::StatementContext &stmtCtx); 100 101 /// DEPRECATED: NEW CODE SHOULD USE THE VERSION OF genIntrinsicCall WITHOUT A 102 /// StatementContext, DECLARED IN IntrinsicCall.h 103 /// Generate the FIR+MLIR operations for the generic intrinsic \p name 104 /// with argument \p args and expected result type \p resultType. 105 /// Returned fir::ExtendedValue is the returned Fortran intrinsic value. 106 fir::ExtendedValue 107 genIntrinsicCall(fir::FirOpBuilder &builder, mlir::Location loc, 108 llvm::StringRef name, std::optional<mlir::Type> resultType, 109 llvm::ArrayRef<fir::ExtendedValue> args, 110 StatementContext &stmtCtx, 111 Fortran::lower::AbstractConverter *converter = nullptr); 112 113 } // namespace lower 114 } // namespace Fortran 115 116 #endif // FORTRAN_LOWER_CUSTOMINTRINSICCALL_H 117