Warning: This file is not a C or C++ file. It does not have highlighting.

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

Warning: This file is not a C or C++ file. It does not have highlighting.

source code of flang/include/flang/Lower/CallInterface.h