xref: /llvm-project/flang/include/flang/Lower/CustomIntrinsicCall.h (revision 31dc2b9aa06f998472fa4a7f147a778ebdc80003)
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