FLANG
CallInterface.h
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 <optional>
34
35namespace Fortran::semantics {
36class Symbol;
37}
38
39namespace mlir {
40class Location;
41}
42
43namespace fir {
44class FortranProcedureFlagsEnumAttr;
45}
46
47namespace Fortran::lower {
49class SymMap;
51namespace pft {
52struct FunctionLikeUnit;
53}
54
60class CallerInterface;
61class CalleeInterface;
62template <typename T>
64template <>
66 using FortranEntity = const Fortran::evaluate::ActualArgument *;
67 using FirValue = int;
68};
69template <>
71 using FortranEntity =
72 std::optional<common::Reference<const semantics::Symbol>>;
73 using FirValue = mlir::Value;
74};
75
77template <typename T>
79
94template <typename T>
95class CallInterface {
97
98public:
100 enum class PassEntityBy {
101 BaseAddress,
102 BoxChar,
103 // passing a read-only descriptor
104 Box,
105 // passing a writable descriptor
106 MutableBox,
107 AddressAndLength,
113 CharBoxValueAttribute, // BoxChar with VALUE
114 // Passing a character procedure as a <procedure address, result length>
115 // tuple.
116 CharProcTuple,
117 BoxProcRef
118 };
119
122 enum class Property {
123 BaseAddress,
124 BoxChar,
125 CharAddress,
126 CharLength,
127 CharProcTuple,
128 Box,
129 MutableBox,
130 Value,
131 BoxProcRef
132 };
133
134 using FortranEntity = typename PassedEntityTypes<T>::FortranEntity;
135 using FirValue = typename PassedEntityTypes<T>::FirValue;
136
139 struct FirPlaceHolder {
140 FirPlaceHolder(mlir::Type t, int passedPosition, Property p,
142 : type{t}, passedEntityPosition{passedPosition}, property{p},
143 attributes{attrs} {}
145 mlir::Type type;
149 static constexpr int resultEntityPosition = -1;
155 };
156
161 bool isOptional() const;
163 bool mayBeModifiedByCall() const;
165 bool mayBeReadByCall() const;
167 bool testTKR(Fortran::common::IgnoreTKR flag) const;
169 bool isIntentOut() const;
171 bool mustBeMadeContiguous() const;
173 bool hasValueAttribute() const;
175 bool hasAllocatableAttribute() const;
190 FortranEntity entity;
191 FirValue firArgument;
192 FirValue firLength; /* only for AddressAndLength */
193
196 nullptr;
197 };
198
201 mlir::func::FuncOp getFuncOp() const { return func; }
203 std::size_t getNumFIRArguments() const { return inputs.size(); }
204 std::size_t getNumFIRResults() const { return outputs.size(); }
207 getFIRArgumentAttributes(std::size_t index) const {
208 return inputs[index].attributes;
209 }
210
212
216 return passedArguments;
217 }
218
220 std::optional<PassedEntity> getPassedResult() const { return passedResult; }
222 mlir::FunctionType genFunctionType();
223
226 void
227 determineInterface(bool isImplicit,
229
231 bool callerAllocateResult() const {
232 return mustPassResult() || mustSaveResult();
233 }
234
236 bool mustPassResult() const { return passedResult.has_value(); }
238 bool mustSaveResult() const { return saveResult; }
239
242 return characteristic && characteristic->CanBeCalledViaImplicitInterface();
243 }
244
247 fir::FortranProcedureFlagsEnumAttr
248 getProcedureAttrs(mlir::MLIRContext *) const;
249
250protected:
253 T &side() { return *static_cast<T *>(this); }
254 const T &side() const { return *static_cast<const T *>(this); }
257 void declare();
260 void mapPassedEntities();
261 void mapBackInputToPassedEntity(const FirPlaceHolder &, FirValue);
262
265 mlir::func::FuncOp func;
266 llvm::SmallVector<PassedEntity> passedArguments;
267 std::optional<PassedEntity> passedResult;
268 bool saveResult = false;
269
273 std::optional<Fortran::evaluate::characteristics::Procedure> characteristic =
274 std::nullopt;
275};
276
277//===----------------------------------------------------------------------===//
278// Caller side interface
279//===----------------------------------------------------------------------===//
280
285class CallerInterface : public CallInterface<CallerInterface> {
286public:
287 CallerInterface(const Fortran::evaluate::ProcedureRef &p,
289 : CallInterface{c}, procRef{p} {
290 declare();
292 actualInputs.resize(getNumFIRArguments());
293 }
294
296 bool hasAlternateReturns() const;
297 std::string getMangledName() const;
298 mlir::Location getCalleeLocation() const;
300
301 const Fortran::evaluate::ProcedureRef &getCallDescription() const {
302 return procRef;
303 }
304
308
309 bool isMainProgram() const { return false; }
310
313 bool isIndirectCall() const;
314
317 bool requireDispatchCall() const;
318
321 std::optional<unsigned> getPassArgIndex() const;
322
326 mlir::Value getIfPassedArg() const;
327
331
336 getDummySymbol(const PassedEntity &entity) const;
337
340 void placeInput(const PassedEntity &passedEntity, mlir::Value arg);
341 void placeAddressAndLengthInput(const PassedEntity &passedEntity,
342 mlir::Value addr, mlir::Value len);
343
345 mlir::Value getInput(const PassedEntity &passedEntity);
346
350
353 if (!verifyActualInputs())
354 llvm::report_fatal_error("lowered arguments are incomplete");
355 return actualInputs;
356 }
357
365 bool mustMapInterfaceSymbolsForDummyArgument(const PassedEntity &) const;
366
370 std::function<void(evaluate::Expr<evaluate::SomeType>, bool)>;
371
373 void walkResultExtents(const ExprVisitor &) const;
374
376 void walkResultLengths(const ExprVisitor &) const;
378 void walkDummyArgumentExtents(const PassedEntity &,
379 const ExprVisitor &) const;
381 void walkDummyArgumentLengths(const PassedEntity &,
382 const ExprVisitor &) const;
383
387 mlir::Value getArgumentValue(const semantics::Symbol &sym) const;
388
393
396 mlir::Type getResultStorageType() const;
397
399 mlir::Type getDummyArgumentType(const PassedEntity &) const;
400
401 // Copy of base implementation.
402 static constexpr bool hasHostAssociated() { return false; }
403 mlir::Type getHostAssociatedTy() const {
404 llvm_unreachable("getting host associated type in CallerInterface");
405 }
406
407 std::optional<mlir::Value> getOriginalPassArg() const {
408 return originalPassArg;
409 }
410 void setOriginalPassArg(mlir::Value x) { originalPassArg = x; }
411
412private:
414 bool verifyActualInputs() const;
415 const Fortran::evaluate::ProcedureRef &procRef;
416 llvm::SmallVector<mlir::Value> actualInputs;
417 std::optional<mlir::Value> originalPassArg;
418};
419
420//===----------------------------------------------------------------------===//
421// Callee side interface
422//===----------------------------------------------------------------------===//
423
426class CalleeInterface : public CallInterface<CalleeInterface> {
427public:
428 CalleeInterface(Fortran::lower::pft::FunctionLikeUnit &f,
430 : CallInterface{c}, funit{f} {
431 declare();
432 }
433
434 bool hasAlternateReturns() const;
435 std::string getMangledName() const;
436 mlir::Location getCalleeLocation() const;
438 bool isMainProgram() const;
439
440 Fortran::lower::pft::FunctionLikeUnit &getCallDescription() const {
441 return funit;
442 }
443
446 bool isIndirectCall() const { return false; }
447
450 bool requireDispatchCall() const { return false; };
451
455
458 mlir::func::FuncOp addEntryBlockAndMapArguments();
459
460 bool hasHostAssociated() const;
461 mlir::Type getHostAssociatedTy() const;
462 mlir::Value getHostAssociatedTuple() const;
463
464private:
466};
467
469mlir::FunctionType
472
479mlir::func::FuncOp
482
487mlir::Type getDummyProcedureType(const Fortran::semantics::Symbol &dummyProc,
489
492mlir::Type
495
497mlir::Type getUntypedBoxProcType(mlir::MLIRContext *context);
498
501bool isCPtrArgByValueType(mlir::Type ty);
502
504// This is required to convey the length of character functions passed as dummy
505// procedures.
509
510} // namespace Fortran::lower
511
512#endif // FORTRAN_LOWER_FIRBUILDER_H
Definition common.h:222
Definition call.h:348
Definition AbstractConverter.h:87
Implementation helper.
Definition CallInterface.cpp:945
Definition CallInterface.h:95
void declare()
Definition CallInterface.cpp:798
bool mustPassResult() const
Is the Fortran result passed as an extra MLIR argument ?
Definition CallInterface.h:236
llvm::SmallVector< mlir::Type > getResultType() const
Return the MLIR output types.
Definition CallInterface.cpp:1684
llvm::ArrayRef< mlir::NamedAttribute > getFIRArgumentAttributes(std::size_t index) const
Return the MLIR attributes of the MLIR input at index.
Definition CallInterface.h:207
llvm::ArrayRef< PassedEntity > getPassedArguments() const
Definition CallInterface.h:215
bool callerAllocateResult() const
Does the caller need to allocate storage for the result ?
Definition CallInterface.h:231
std::size_t getNumFIRArguments() const
Number of MLIR inputs/outputs of the created FuncOp.
Definition CallInterface.h:203
std::optional< Fortran::evaluate::characteristics::Procedure > characteristic
Definition CallInterface.h:273
void mapPassedEntities()
Definition CallInterface.cpp:860
mlir::func::FuncOp getFuncOp() const
Definition CallInterface.h:201
T & side()
CRTP handle.
Definition CallInterface.h:253
bool canBeCalledViaImplicitInterface() const
Can the associated procedure be called via an implicit interface?
Definition CallInterface.h:241
void determineInterface(bool isImplicit, const Fortran::evaluate::characteristics::Procedure &)
Definition CallInterface.cpp:1653
PassEntityBy
Enum the different ways an entity can be passed-by.
Definition CallInterface.h:100
@ BaseAddressValueAttribute
ValueAttribute means dummy has the Fortran VALUE attribute.
Definition CallInterface.h:112
@ Value
Definition CallInterface.h:110
mlir::FunctionType genFunctionType()
Returns the mlir function type.
Definition CallInterface.cpp:1671
bool mustSaveResult() const
Must the MLIR result be saved with a fir.save_result ?
Definition CallInterface.h:238
Property
Definition CallInterface.h:122
std::optional< PassedEntity > getPassedResult() const
Definition CallInterface.h:220
fir::FortranProcedureFlagsEnumAttr getProcedureAttrs(mlir::MLIRContext *) const
Definition CallInterface.cpp:1693
Definition CallInterface.h:426
mlir::func::FuncOp addEntryBlockAndMapArguments()
Definition CallInterface.cpp:656
const Fortran::semantics::Symbol * getProcedureSymbol() const
Definition CallInterface.cpp:628
bool isIndirectCall() const
Definition CallInterface.h:446
bool requireDispatchCall() const
Definition CallInterface.h:450
Definition CallInterface.h:285
std::function< void(evaluate::Expr< evaluate::SomeType >, bool)> ExprVisitor
Definition CallInterface.h:369
const Fortran::semantics::SubprogramDetails * getInterfaceDetails() const
Definition CallInterface.cpp:604
mlir::Value getIfPassedArg() const
Definition CallInterface.cpp:176
bool mustMapInterfaceSymbolsForResult() const
Definition CallInterface.cpp:518
mlir::Type getDummyArgumentType(const PassedEntity &) const
Return FIR type of argument.
Definition CallInterface.cpp:587
mlir::Value getInput(const PassedEntity &passedEntity)
Get lowered FIR argument given the Fortran argument.
Definition CallInterface.cpp:420
void walkDummyArgumentExtents(const PassedEntity &, const ExprVisitor &) const
Walk non-deferred extent specification expressions of a dummy argument.
Definition CallInterface.cpp:507
void walkDummyArgumentLengths(const PassedEntity &, const ExprVisitor &) const
Walk non-deferred length specification expressions of a dummy argument.
Definition CallInterface.cpp:455
bool requireDispatchCall() const
Definition CallInterface.cpp:130
const Fortran::evaluate::ProcedureDesignator * getIfIndirectCall() const
Definition CallInterface.cpp:186
bool mustMapInterfaceSymbolsForDummyArgument(const PassedEntity &) const
Definition CallInterface.cpp:534
const Fortran::semantics::Symbol * getProcedureSymbol() const
Definition CallInterface.cpp:115
bool isIndirectCall() const
Definition CallInterface.cpp:123
void placeInput(const PassedEntity &passedEntity, mlir::Value arg)
Definition CallInterface.cpp:389
const Fortran::semantics::Symbol * getDummySymbol(const PassedEntity &entity) const
Definition CallInterface.cpp:563
void walkResultExtents(const ExprVisitor &) const
Walk the result non-deferred extent specification expressions.
Definition CallInterface.cpp:491
std::optional< unsigned > getPassArgIndex() const
Definition CallInterface.cpp:152
mlir::Type getResultStorageType() const
Definition CallInterface.cpp:580
const Fortran::semantics::Symbol & getResultSymbol() const
Definition CallInterface.cpp:593
mlir::Value getArgumentValue(const semantics::Symbol &sym) const
Definition CallInterface.cpp:545
void walkResultLengths(const ExprVisitor &) const
Walk the result non-deferred length specification expressions.
Definition CallInterface.cpp:444
bool hasAlternateReturns() const
CRTP callbacks.
Definition CallInterface.cpp:63
llvm::ArrayRef< mlir::Value > getInputs() const
Get the input vector once it is complete.
Definition CallInterface.h:352
Definition HostAssociations.h:28
Definition SymbolMap.h:181
Definition symbol.h:918
Definition FIRType.h:106
Definition OpenACC.h:20
Definition ParserActions.h:24
bool mustPassLengthWithDummyProcedure(const Fortran::evaluate::ProcedureDesignator &proc, Fortran::lower::AbstractConverter &)
Is it required to pass proc as a tuple<function address, result length> ?
Definition CallInterface.cpp:1892
mlir::FunctionType translateSignature(const Fortran::evaluate::ProcedureDesignator &, Fortran::lower::AbstractConverter &)
Translate a procedure characteristics to an mlir::FunctionType signature.
Definition CallInterface.cpp:1860
bool isCPtrArgByValueType(mlir::Type ty)
Definition CallInterface.cpp:1925
mlir::func::FuncOp getOrDeclareFunction(const Fortran::evaluate::ProcedureDesignator &, Fortran::lower::AbstractConverter &)
Definition CallInterface.cpp:1866
mlir::Type getDummyProcedurePointerType(const Fortran::semantics::Symbol &dummyProcPtr, Fortran::lower::AbstractConverter &)
Definition CallInterface.cpp:1914
mlir::Type getUntypedBoxProcType(mlir::MLIRContext *context)
Return !fir.boxproc<() -> ()> type.
Definition CallInterface.cpp:36
mlir::Type getDummyProcedureType(const Fortran::semantics::Symbol &dummyProc, Fortran::lower::AbstractConverter &)
Definition CallInterface.cpp:1901
Definition AbstractConverter.h:37
Definition AbstractConverter.h:32
Definition characteristics.h:346
int passedEntityPosition
Definition CallInterface.h:148
Property property
Definition CallInterface.h:152
llvm::SmallVector< mlir::NamedAttribute > attributes
MLIR attributes for this argument.
Definition CallInterface.h:154
mlir::Type type
Type for this input/output.
Definition CallInterface.h:145
Definition CallInterface.h:159
FortranEntity entity
Definition CallInterface.h:190
bool testTKR(Fortran::common::IgnoreTKR flag) const
Does the argument have the specified IgnoreTKR flag?
Definition CallInterface.cpp:1538
bool mayRequireIntentoutFinalization() const
Definition CallInterface.cpp:1604
bool mayBeModifiedByCall() const
Can the argument be modified by the callee?
Definition CallInterface.cpp:1522
bool mayBeReadByCall() const
Can the argument be read by the callee?
Definition CallInterface.cpp:1531
bool hasValueAttribute() const
Does the dummy argument have the VALUE attribute?
Definition CallInterface.cpp:1579
bool isIntentOut() const
Is the argument INTENT(OUT)
Definition CallInterface.cpp:1551
bool hasAllocatableAttribute() const
Does the dummy argument have the ALLOCATABLE attribute?
Definition CallInterface.cpp:1591
const Fortran::evaluate::characteristics::DummyArgument * characteristics
Pointer to the argument characteristics. Nullptr for results.
Definition CallInterface.h:195
bool isSequenceAssociatedDescriptor() const
Definition CallInterface.cpp:1643
PassEntityBy passBy
How entity is passed by.
Definition CallInterface.h:186
bool mustBeMadeContiguous() const
Does the argument have the CONTIGUOUS attribute or have explicit shape?
Definition CallInterface.cpp:1557
bool isOptional() const
Is the dummy argument optional?
Definition CallInterface.cpp:1516
Definition CallInterface.h:63
Definition PFTBuilder.h:681