xref: /llvm-project/flang/include/flang/Lower/CallInterface.h (revision d9250061e10b82f82d9833009f6565775578ee58)
1 //===-- Lower/CallInterface.h -- Procedure call interface ------*- 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 // Utility that defines fir call interface for procedure both on caller and
14 // and callee side and get the related FuncOp.
15 // It does not emit any FIR code but for the created mlir::func::FuncOp, instead
16 // it provides back a container of Symbol (callee side)/ActualArgument (caller
17 // side) with additional information for each element describing how it must be
18 // plugged with the mlir::func::FuncOp.
19 // It handles the fact that hidden arguments may be inserted for the result.
20 // while lowering.
21 //
22 // This utility uses the characteristic of Fortran procedures to operate, which
23 // is a term and concept used in Fortran to refer to the signature of a function
24 // or subroutine.
25 //===----------------------------------------------------------------------===//
26 
27 #ifndef FORTRAN_LOWER_CALLINTERFACE_H
28 #define FORTRAN_LOWER_CALLINTERFACE_H
29 
30 #include "flang/Common/reference.h"
31 #include "flang/Evaluate/characteristics.h"
32 #include "mlir/Dialect/Func/IR/FuncOps.h"
33 #include "mlir/IR/BuiltinOps.h"
34 #include <memory>
35 #include <optional>
36 
37 namespace Fortran::semantics {
38 class Symbol;
39 }
40 
41 namespace mlir {
42 class Location;
43 }
44 
45 namespace fir {
46 class FortranProcedureFlagsEnumAttr;
47 }
48 
49 namespace Fortran::lower {
50 class AbstractConverter;
51 class SymMap;
52 class HostAssociations;
53 namespace pft {
54 struct FunctionLikeUnit;
55 }
56 
57 /// PassedEntityTypes helps abstract whether CallInterface is mapping a
58 /// Symbol to mlir::Value (callee side) or an ActualArgument to a position
59 /// inside the input vector for the CallOp (caller side. It will be up to the
60 /// CallInterface user to produce the mlir::Value that will go in this input
61 /// vector).
62 class CallerInterface;
63 class CalleeInterface;
64 template <typename T>
65 struct PassedEntityTypes {};
66 template <>
67 struct PassedEntityTypes<CallerInterface> {
68   using FortranEntity = const Fortran::evaluate::ActualArgument *;
69   using FirValue = int;
70 };
71 template <>
72 struct PassedEntityTypes<CalleeInterface> {
73   using FortranEntity =
74       std::optional<common::Reference<const semantics::Symbol>>;
75   using FirValue = mlir::Value;
76 };
77 
78 /// Implementation helper
79 template <typename T>
80 class CallInterfaceImpl;
81 
82 /// CallInterface defines all the logic to determine FIR function interfaces
83 /// from a characteristic, build the mlir::func::FuncOp and describe back the
84 /// argument mapping to its user.
85 /// The logic is shared between the callee and caller sides that it accepts as
86 /// a curiously recursive template to handle the few things that cannot be
87 /// shared between both sides (getting characteristics, mangled name, location).
88 /// It maps FIR arguments to front-end Symbol (callee side) or ActualArgument
89 /// (caller side) with the same code using the abstract FortranEntity type that
90 /// can be either a Symbol or an ActualArgument.
91 /// It works in two passes: a first pass over the characteristics that decides
92 /// how the interface must be. Then, the funcOp is created for it. Then a simple
93 /// pass over fir arguments finalize the interface information that must be
94 /// passed back to the user (and may require having the funcOp). All this
95 /// passes are driven from the CallInterface constructor.
96 template <typename T>
97 class CallInterface {
98   friend CallInterfaceImpl<T>;
99 
100 public:
101   /// Enum the different ways an entity can be passed-by
102   enum class PassEntityBy {
103     BaseAddress,
104     BoxChar,
105     // passing a read-only descriptor
106     Box,
107     // passing a writable descriptor
108     MutableBox,
109     AddressAndLength,
110     /// Value means passed by value at the mlir level, it is not necessarily
111     /// implied by Fortran Value attribute.
112     Value,
113     /// ValueAttribute means dummy has the Fortran VALUE attribute.
114     BaseAddressValueAttribute,
115     CharBoxValueAttribute, // BoxChar with VALUE
116     // Passing a character procedure as a <procedure address, result length>
117     // tuple.
118     CharProcTuple,
119     BoxProcRef
120   };
121   /// Different properties of an entity that can be passed/returned.
122   /// One-to-One mapping with PassEntityBy but for
123   /// PassEntityBy::AddressAndLength that has two properties.
124   enum class Property {
125     BaseAddress,
126     BoxChar,
127     CharAddress,
128     CharLength,
129     CharProcTuple,
130     Box,
131     MutableBox,
132     Value,
133     BoxProcRef
134   };
135 
136   using FortranEntity = typename PassedEntityTypes<T>::FortranEntity;
137   using FirValue = typename PassedEntityTypes<T>::FirValue;
138 
139   /// FirPlaceHolder are place holders for the mlir inputs and outputs that are
140   /// created during the first pass before the mlir::func::FuncOp is created.
141   struct FirPlaceHolder {
142     FirPlaceHolder(mlir::Type t, int passedPosition, Property p,
143                    llvm::ArrayRef<mlir::NamedAttribute> attrs)
144         : type{t}, passedEntityPosition{passedPosition}, property{p},
145           attributes{attrs} {}
146     /// Type for this input/output
147     mlir::Type type;
148     /// Position of related passedEntity in passedArguments.
149     /// (passedEntity is the passedResult this value is resultEntityPosition.
150     int passedEntityPosition;
151     static constexpr int resultEntityPosition = -1;
152     /// Indicate property of the entity passedEntityPosition that must be passed
153     /// through this argument.
154     Property property;
155     /// MLIR attributes for this argument
156     llvm::SmallVector<mlir::NamedAttribute> attributes;
157   };
158 
159   /// PassedEntity is what is provided back to the CallInterface user.
160   /// It describe how the entity is plugged in the interface
161   struct PassedEntity {
162     /// Is the dummy argument optional?
163     bool isOptional() const;
164     /// Can the argument be modified by the callee?
165     bool mayBeModifiedByCall() const;
166     /// Can the argument be read by the callee?
167     bool mayBeReadByCall() const;
168     /// Does the argument have the specified IgnoreTKR flag?
169     bool testTKR(Fortran::common::IgnoreTKR flag) const;
170     /// Is the argument INTENT(OUT)
171     bool isIntentOut() const;
172     /// Does the argument have the CONTIGUOUS attribute or have explicit shape?
173     bool mustBeMadeContiguous() const;
174     /// Does the dummy argument have the VALUE attribute?
175     bool hasValueAttribute() const;
176     /// Does the dummy argument have the ALLOCATABLE attribute?
177     bool hasAllocatableAttribute() const;
178     /// May the dummy argument require INTENT(OUT) finalization
179     /// on entry to the invoked procedure? Provides conservative answer.
180     bool mayRequireIntentoutFinalization() const;
181     /// Is the dummy argument an explicit-shape or assumed-size array that
182     /// must be passed by descriptor? Sequence association imply the actual
183     /// argument shape/rank may differ with the dummy shape/rank (see F'2023
184     /// section 15.5.2.12), so care is needed when creating the descriptor
185     /// for the dummy argument.
186     bool isSequenceAssociatedDescriptor() const;
187     /// How entity is passed by.
188     PassEntityBy passBy;
189     /// What is the entity (SymbolRef for callee/ActualArgument* for caller)
190     /// What is the related mlir::func::FuncOp argument(s) (mlir::Value for
191     /// callee / index for the caller).
192     FortranEntity entity;
193     FirValue firArgument;
194     FirValue firLength; /* only for AddressAndLength */
195 
196     /// Pointer to the argument characteristics. Nullptr for results.
197     const Fortran::evaluate::characteristics::DummyArgument *characteristics =
198         nullptr;
199   };
200 
201   /// Return the mlir::func::FuncOp. Note that front block is added by this
202   /// utility if callee side.
203   mlir::func::FuncOp getFuncOp() const { return func; }
204   /// Number of MLIR inputs/outputs of the created FuncOp.
205   std::size_t getNumFIRArguments() const { return inputs.size(); }
206   std::size_t getNumFIRResults() const { return outputs.size(); }
207   /// Return the MLIR output types.
208   llvm::SmallVector<mlir::Type> getResultType() const;
209 
210   /// Return a container of Symbol/ActualArgument* and how they must
211   /// be plugged with the mlir::func::FuncOp.
212   llvm::ArrayRef<PassedEntity> getPassedArguments() const {
213     return passedArguments;
214   }
215   /// In case the result must be passed by the caller, indicate how.
216   /// nullopt if the result is not passed by the caller.
217   std::optional<PassedEntity> getPassedResult() const { return passedResult; }
218   /// Returns the mlir function type
219   mlir::FunctionType genFunctionType();
220 
221   /// determineInterface is the entry point of the first pass that defines the
222   /// interface and is required to get the mlir::func::FuncOp.
223   void
224   determineInterface(bool isImplicit,
225                      const Fortran::evaluate::characteristics::Procedure &);
226 
227   /// Does the caller need to allocate storage for the result ?
228   bool callerAllocateResult() const {
229     return mustPassResult() || mustSaveResult();
230   }
231 
232   /// Is the Fortran result passed as an extra MLIR argument ?
233   bool mustPassResult() const { return passedResult.has_value(); }
234   /// Must the MLIR result be saved with a fir.save_result ?
235   bool mustSaveResult() const { return saveResult; }
236 
237   /// Can the associated procedure be called via an implicit interface?
238   bool canBeCalledViaImplicitInterface() const {
239     return characteristic && characteristic->CanBeCalledViaImplicitInterface();
240   }
241 
242   /// Translate Fortran procedure attributes into FIR attribute.
243   /// Return attribute is nullptr if the procedure has no attributes.
244   fir::FortranProcedureFlagsEnumAttr
245   getProcedureAttrs(mlir::MLIRContext *) const;
246 
247 protected:
248   CallInterface(Fortran::lower::AbstractConverter &c) : converter{c} {}
249   /// CRTP handle.
250   T &side() { return *static_cast<T *>(this); }
251   const T &side() const { return *static_cast<const T *>(this); }
252   /// Entry point to be called by child ctor to analyze the signature and
253   /// create/find the mlir::func::FuncOp. Child needs to be initialized first.
254   void declare();
255   /// Second pass entry point, once the mlir::func::FuncOp is created.
256   /// Nothing is done if it was already called.
257   void mapPassedEntities();
258   void mapBackInputToPassedEntity(const FirPlaceHolder &, FirValue);
259 
260   llvm::SmallVector<FirPlaceHolder> outputs;
261   llvm::SmallVector<FirPlaceHolder> inputs;
262   mlir::func::FuncOp func;
263   llvm::SmallVector<PassedEntity> passedArguments;
264   std::optional<PassedEntity> passedResult;
265   bool saveResult = false;
266 
267   Fortran::lower::AbstractConverter &converter;
268   /// Store characteristic once created, it is required for further information
269   /// (e.g. getting the length of character result)
270   std::optional<Fortran::evaluate::characteristics::Procedure> characteristic =
271       std::nullopt;
272 };
273 
274 //===----------------------------------------------------------------------===//
275 // Caller side interface
276 //===----------------------------------------------------------------------===//
277 
278 /// The CallerInterface provides the helpers needed by CallInterface
279 /// (getting the characteristic...) and a safe way for the user to
280 /// place the mlir::Value arguments into the input vector
281 /// once they are lowered.
282 class CallerInterface : public CallInterface<CallerInterface> {
283 public:
284   CallerInterface(const Fortran::evaluate::ProcedureRef &p,
285                   Fortran::lower::AbstractConverter &c)
286       : CallInterface{c}, procRef{p} {
287     declare();
288     mapPassedEntities();
289     actualInputs.resize(getNumFIRArguments());
290   }
291 
292   /// CRTP callbacks
293   bool hasAlternateReturns() const;
294   std::string getMangledName() const;
295   mlir::Location getCalleeLocation() const;
296   Fortran::evaluate::characteristics::Procedure characterize() const;
297 
298   const Fortran::evaluate::ProcedureRef &getCallDescription() const {
299     return procRef;
300   }
301 
302   /// Get the SubprogramDetails that defines the interface of this call if it is
303   /// known at the call site. Return nullptr if it is not known.
304   const Fortran::semantics::SubprogramDetails *getInterfaceDetails() const;
305 
306   bool isMainProgram() const { return false; }
307 
308   /// Returns true if this is a call to a procedure pointer of a dummy
309   /// procedure.
310   bool isIndirectCall() const;
311 
312   /// Returns true if this is a call of a type-bound procedure with a
313   /// polymorphic entity.
314   bool requireDispatchCall() const;
315 
316   /// Get the passed-object argument index. nullopt if there is no passed-object
317   /// index.
318   std::optional<unsigned> getPassArgIndex() const;
319 
320   /// Get the passed-object if any. Crashes if there is a passed object
321   /// but it was not placed in the inputs yet. Return a null value
322   /// otherwise.
323   mlir::Value getIfPassedArg() const;
324 
325   /// Return the procedure symbol if this is a call to a user defined
326   /// procedure.
327   const Fortran::semantics::Symbol *getProcedureSymbol() const;
328 
329   /// Return the dummy argument symbol if this is a call to a user
330   /// defined procedure with explicit interface. Returns nullptr if there
331   /// is no user defined explicit interface.
332   const Fortran::semantics::Symbol *
333   getDummySymbol(const PassedEntity &entity) const;
334 
335   /// Helpers to place the lowered arguments at the right place once they
336   /// have been lowered.
337   void placeInput(const PassedEntity &passedEntity, mlir::Value arg);
338   void placeAddressAndLengthInput(const PassedEntity &passedEntity,
339                                   mlir::Value addr, mlir::Value len);
340 
341   /// Get lowered FIR argument given the Fortran argument.
342   mlir::Value getInput(const PassedEntity &passedEntity);
343 
344   /// If this is a call to a procedure pointer or dummy, returns the related
345   /// procedure designator. Nullptr otherwise.
346   const Fortran::evaluate::ProcedureDesignator *getIfIndirectCall() const;
347 
348   /// Get the input vector once it is complete.
349   llvm::ArrayRef<mlir::Value> getInputs() const {
350     if (!verifyActualInputs())
351       llvm::report_fatal_error("lowered arguments are incomplete");
352     return actualInputs;
353   }
354 
355   /// Does the caller must map function interface symbols in order to evaluate
356   /// the result specification expressions (extents and lengths) ? If needed,
357   /// this mapping must be done after argument lowering, and before the call
358   /// itself.
359   bool mustMapInterfaceSymbolsForResult() const;
360   /// Must the caller map function interface symbols in order to evaluate
361   /// the specification expressions of a given dummy argument?
362   bool mustMapInterfaceSymbolsForDummyArgument(const PassedEntity &) const;
363 
364   /// Visitor for specification expression. Boolean indicate the specification
365   /// expression is for the last extent of an assumed size array.
366   using ExprVisitor =
367       std::function<void(evaluate::Expr<evaluate::SomeType>, bool)>;
368 
369   /// Walk the result non-deferred extent specification expressions.
370   void walkResultExtents(const ExprVisitor &) const;
371 
372   /// Walk the result non-deferred length specification expressions.
373   void walkResultLengths(const ExprVisitor &) const;
374   /// Walk non-deferred extent specification expressions of a dummy argument.
375   void walkDummyArgumentExtents(const PassedEntity &,
376                                 const ExprVisitor &) const;
377   /// Walk non-deferred length specification expressions of a dummy argument.
378   void walkDummyArgumentLengths(const PassedEntity &,
379                                 const ExprVisitor &) const;
380 
381   /// Get the mlir::Value that is passed as argument \p sym of the function
382   /// being called. The arguments must have been placed before calling this
383   /// function.
384   mlir::Value getArgumentValue(const semantics::Symbol &sym) const;
385 
386   /// Returns the symbol for the result in the explicit interface. If this is
387   /// called on an intrinsic or function without explicit interface, this will
388   /// crash.
389   const Fortran::semantics::Symbol &getResultSymbol() const;
390 
391   /// If some storage needs to be allocated for the result,
392   /// returns the storage type.
393   mlir::Type getResultStorageType() const;
394 
395   /// Return FIR type of argument.
396   mlir::Type getDummyArgumentType(const PassedEntity &) const;
397 
398   // Copy of base implementation.
399   static constexpr bool hasHostAssociated() { return false; }
400   mlir::Type getHostAssociatedTy() const {
401     llvm_unreachable("getting host associated type in CallerInterface");
402   }
403 
404 private:
405   /// Check that the input vector is complete.
406   bool verifyActualInputs() const;
407   const Fortran::evaluate::ProcedureRef &procRef;
408   llvm::SmallVector<mlir::Value> actualInputs;
409 };
410 
411 //===----------------------------------------------------------------------===//
412 // Callee side interface
413 //===----------------------------------------------------------------------===//
414 
415 /// CalleeInterface only provides the helpers needed by CallInterface
416 /// to abstract the specificities of the callee side.
417 class CalleeInterface : public CallInterface<CalleeInterface> {
418 public:
419   CalleeInterface(Fortran::lower::pft::FunctionLikeUnit &f,
420                   Fortran::lower::AbstractConverter &c)
421       : CallInterface{c}, funit{f} {
422     declare();
423   }
424 
425   bool hasAlternateReturns() const;
426   std::string getMangledName() const;
427   mlir::Location getCalleeLocation() const;
428   Fortran::evaluate::characteristics::Procedure characterize() const;
429   bool isMainProgram() const;
430 
431   Fortran::lower::pft::FunctionLikeUnit &getCallDescription() const {
432     return funit;
433   }
434 
435   /// On the callee side it does not matter whether the procedure is
436   /// called through pointers or not.
437   bool isIndirectCall() const { return false; }
438 
439   /// On the callee side it does not matter whether the procedure is called
440   /// through dynamic dispatch or not.
441   bool requireDispatchCall() const { return false; };
442 
443   /// Return the procedure symbol if this is a call to a user defined
444   /// procedure.
445   const Fortran::semantics::Symbol *getProcedureSymbol() const;
446 
447   /// Add mlir::func::FuncOp entry block and map fir block arguments to Fortran
448   /// dummy argument symbols.
449   mlir::func::FuncOp addEntryBlockAndMapArguments();
450 
451   bool hasHostAssociated() const;
452   mlir::Type getHostAssociatedTy() const;
453   mlir::Value getHostAssociatedTuple() const;
454 
455 private:
456   Fortran::lower::pft::FunctionLikeUnit &funit;
457 };
458 
459 /// Translate a procedure characteristics to an mlir::FunctionType signature.
460 mlir::FunctionType
461 translateSignature(const Fortran::evaluate::ProcedureDesignator &,
462                    Fortran::lower::AbstractConverter &);
463 
464 /// Declare or find the mlir::func::FuncOp for the procedure designator
465 /// \p proc. If the mlir::func::FuncOp does not exist yet, declare it with
466 /// the signature translated from the ProcedureDesignator argument.
467 /// Due to Fortran implicit function typing rules, the returned FuncOp is not
468 /// guaranteed to have the signature from ProcedureDesignator if the FuncOp was
469 /// already declared.
470 mlir::func::FuncOp
471 getOrDeclareFunction(const Fortran::evaluate::ProcedureDesignator &,
472                      Fortran::lower::AbstractConverter &);
473 
474 /// Return the type of an argument that is a dummy procedure. This may be an
475 /// mlir::FunctionType, but it can also be a more elaborate type based on the
476 /// function type (like a tuple<function type, length type> for character
477 /// functions).
478 mlir::Type getDummyProcedureType(const Fortran::semantics::Symbol &dummyProc,
479                                  Fortran::lower::AbstractConverter &);
480 
481 /// Return !fir.boxproc<() -> ()> type.
482 mlir::Type getUntypedBoxProcType(mlir::MLIRContext *context);
483 
484 /// Return true if \p ty is "!fir.ref<i64>", which is the interface for
485 /// type(C_PTR/C_FUNPTR) passed by value.
486 bool isCPtrArgByValueType(mlir::Type ty);
487 
488 /// Is it required to pass \p proc as a tuple<function address, result length> ?
489 // This is required to convey  the length of character functions passed as dummy
490 // procedures.
491 bool mustPassLengthWithDummyProcedure(
492     const Fortran::evaluate::ProcedureDesignator &proc,
493     Fortran::lower::AbstractConverter &);
494 
495 } // namespace Fortran::lower
496 
497 #endif // FORTRAN_LOWER_FIRBUILDER_H
498