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 "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 fir {
46class FortranProcedureFlagsEnumAttr;
47}
48
49namespace Fortran::lower {
50class AbstractConverter;
51class SymMap;
52class HostAssociations;
53namespace pft {
54struct FunctionLikeUnit;
55}
56
62class CallerInterface;
63class CalleeInterface;
64template <typename T>
66template <>
69 using FirValue = int;
70};
71template <>
73 using FortranEntity =
74 std::optional<common::Reference<const semantics::Symbol>>;
75 using FirValue = mlir::Value;
76};
77
79template <typename T>
81
96template <typename T>
99
100public:
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,
112 Value,
115 CharBoxValueAttribute, // BoxChar with VALUE
116 // Passing a character procedure as a <procedure address, result length>
117 // tuple.
118 CharProcTuple,
119 BoxProcRef
120 };
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
142 FirPlaceHolder(mlir::Type t, int passedPosition, Property p,
144 : type{t}, passedEntityPosition{passedPosition}, property{p},
145 attributes{attrs} {}
147 mlir::Type type;
151 static constexpr int resultEntityPosition = -1;
157 };
158
163 bool isOptional() const;
165 bool mayBeModifiedByCall() const;
167 bool mayBeReadByCall() const;
169 bool testTKR(Fortran::common::IgnoreTKR flag) const;
171 bool isIntentOut() const;
173 bool mustBeMadeContiguous() const;
175 bool hasValueAttribute() const;
177 bool hasAllocatableAttribute() const;
192 FortranEntity entity;
193 FirValue firArgument;
194 FirValue firLength; /* only for AddressAndLength */
195
198 nullptr;
199 };
200
203 mlir::func::FuncOp getFuncOp() const { return func; }
205 std::size_t getNumFIRArguments() const { return inputs.size(); }
206 std::size_t getNumFIRResults() const { return outputs.size(); }
209
213 return passedArguments;
214 }
217 std::optional<PassedEntity> getPassedResult() const { return passedResult; }
219 mlir::FunctionType genFunctionType();
220
223 void
224 determineInterface(bool isImplicit,
226
228 bool callerAllocateResult() const {
229 return mustPassResult() || mustSaveResult();
230 }
231
233 bool mustPassResult() const { return passedResult.has_value(); }
235 bool mustSaveResult() const { return saveResult; }
236
239 return characteristic && characteristic->CanBeCalledViaImplicitInterface();
240 }
241
244 fir::FortranProcedureFlagsEnumAttr
245 getProcedureAttrs(mlir::MLIRContext *) const;
246
247protected:
250 T &side() { return *static_cast<T *>(this); }
251 const T &side() const { return *static_cast<const T *>(this); }
254 void declare();
257 void mapPassedEntities();
258 void mapBackInputToPassedEntity(const FirPlaceHolder &, FirValue);
259
262 mlir::func::FuncOp func;
263 llvm::SmallVector<PassedEntity> passedArguments;
264 std::optional<PassedEntity> passedResult;
265 bool saveResult = false;
266
270 std::optional<Fortran::evaluate::characteristics::Procedure> characteristic =
271 std::nullopt;
272};
273
274//===----------------------------------------------------------------------===//
275// Caller side interface
276//===----------------------------------------------------------------------===//
277
282class CallerInterface : public CallInterface<CallerInterface> {
283public:
286 : CallInterface{c}, procRef{p} {
287 declare();
289 actualInputs.resize(getNumFIRArguments());
290 }
291
293 bool hasAlternateReturns() const;
294 std::string getMangledName() const;
295 mlir::Location getCalleeLocation() const;
297
298 const Fortran::evaluate::ProcedureRef &getCallDescription() const {
299 return procRef;
300 }
301
305
306 bool isMainProgram() const { return false; }
307
310 bool isIndirectCall() const;
311
314 bool requireDispatchCall() const;
315
318 std::optional<unsigned> getPassArgIndex() const;
319
323 mlir::Value getIfPassedArg() const;
324
328
333 getDummySymbol(const PassedEntity &entity) const;
334
337 void placeInput(const PassedEntity &passedEntity, mlir::Value arg);
338 void placeAddressAndLengthInput(const PassedEntity &passedEntity,
339 mlir::Value addr, mlir::Value len);
340
342 mlir::Value getInput(const PassedEntity &passedEntity);
343
347
350 if (!verifyActualInputs())
351 llvm::report_fatal_error("lowered arguments are incomplete");
352 return actualInputs;
353 }
354
362 bool mustMapInterfaceSymbolsForDummyArgument(const PassedEntity &) const;
363
367 std::function<void(evaluate::Expr<evaluate::SomeType>, bool)>;
368
370 void walkResultExtents(const ExprVisitor &) const;
371
373 void walkResultLengths(const ExprVisitor &) const;
375 void walkDummyArgumentExtents(const PassedEntity &,
376 const ExprVisitor &) const;
378 void walkDummyArgumentLengths(const PassedEntity &,
379 const ExprVisitor &) const;
380
384 mlir::Value getArgumentValue(const semantics::Symbol &sym) const;
385
390
393 mlir::Type getResultStorageType() const;
394
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
404private:
406 bool verifyActualInputs() const;
407 const Fortran::evaluate::ProcedureRef &procRef;
409};
410
411//===----------------------------------------------------------------------===//
412// Callee side interface
413//===----------------------------------------------------------------------===//
414
417class CalleeInterface : public CallInterface<CalleeInterface> {
418public:
421 : CallInterface{c}, funit{f} {
422 declare();
423 }
424
425 bool hasAlternateReturns() const;
426 std::string getMangledName() const;
427 mlir::Location getCalleeLocation() const;
429 bool isMainProgram() const;
430
431 Fortran::lower::pft::FunctionLikeUnit &getCallDescription() const {
432 return funit;
433 }
434
437 bool isIndirectCall() const { return false; }
438
441 bool requireDispatchCall() const { return false; };
442
446
449 mlir::func::FuncOp addEntryBlockAndMapArguments();
450
451 bool hasHostAssociated() const;
452 mlir::Type getHostAssociatedTy() const;
453 mlir::Value getHostAssociatedTuple() const;
454
455private:
457};
458
460mlir::FunctionType
463
470mlir::func::FuncOp
473
478mlir::Type getDummyProcedureType(const Fortran::semantics::Symbol &dummyProc,
480
482mlir::Type getUntypedBoxProcType(mlir::MLIRContext *context);
483
486bool isCPtrArgByValueType(mlir::Type ty);
487
489// This is required to convey the length of character functions passed as dummy
490// procedures.
494
495} // namespace Fortran::lower
496
497#endif // FORTRAN_LOWER_FIRBUILDER_H
Definition: common.h:213
Definition: call.h:232
Definition: AbstractConverter.h:82
Implementation helper.
Definition: CallInterface.cpp:811
Definition: CallInterface.h:97
void declare()
Definition: CallInterface.cpp:681
bool mustPassResult() const
Is the Fortran result passed as an extra MLIR argument ?
Definition: CallInterface.h:233
llvm::SmallVector< mlir::Type > getResultType() const
Return the MLIR output types.
Definition: CallInterface.cpp:1542
llvm::ArrayRef< PassedEntity > getPassedArguments() const
Definition: CallInterface.h:212
bool callerAllocateResult() const
Does the caller need to allocate storage for the result ?
Definition: CallInterface.h:228
std::size_t getNumFIRArguments() const
Number of MLIR inputs/outputs of the created FuncOp.
Definition: CallInterface.h:205
std::optional< Fortran::evaluate::characteristics::Procedure > characteristic
Definition: CallInterface.h:270
void mapPassedEntities()
Definition: CallInterface.cpp:726
mlir::func::FuncOp getFuncOp() const
Definition: CallInterface.h:203
T & side()
CRTP handle.
Definition: CallInterface.h:250
bool canBeCalledViaImplicitInterface() const
Can the associated procedure be called via an implicit interface?
Definition: CallInterface.h:238
void determineInterface(bool isImplicit, const Fortran::evaluate::characteristics::Procedure &)
Definition: CallInterface.cpp:1511
PassEntityBy
Enum the different ways an entity can be passed-by.
Definition: CallInterface.h:102
@ BaseAddressValueAttribute
ValueAttribute means dummy has the Fortran VALUE attribute.
mlir::FunctionType genFunctionType()
Returns the mlir function type.
Definition: CallInterface.cpp:1529
bool mustSaveResult() const
Must the MLIR result be saved with a fir.save_result ?
Definition: CallInterface.h:235
Property
Definition: CallInterface.h:124
std::optional< PassedEntity > getPassedResult() const
Definition: CallInterface.h:217
fir::FortranProcedureFlagsEnumAttr getProcedureAttrs(mlir::MLIRContext *) const
Definition: CallInterface.cpp:1551
Definition: CallInterface.h:417
mlir::func::FuncOp addEntryBlockAndMapArguments()
Definition: CallInterface.cpp:551
const Fortran::semantics::Symbol * getProcedureSymbol() const
Definition: CallInterface.cpp:523
bool isIndirectCall() const
Definition: CallInterface.h:437
bool requireDispatchCall() const
Definition: CallInterface.h:441
Definition: CallInterface.h:282
const Fortran::semantics::SubprogramDetails * getInterfaceDetails() const
Definition: CallInterface.cpp:499
mlir::Value getIfPassedArg() const
Definition: CallInterface.cpp:137
std::function< void(evaluate::Expr< evaluate::SomeType >, bool)> ExprVisitor
Definition: CallInterface.h:367
bool mustMapInterfaceSymbolsForResult() const
Definition: CallInterface.cpp:413
mlir::Type getDummyArgumentType(const PassedEntity &) const
Return FIR type of argument.
Definition: CallInterface.cpp:482
mlir::Value getInput(const PassedEntity &passedEntity)
Get lowered FIR argument given the Fortran argument.
Definition: CallInterface.cpp:315
void walkDummyArgumentExtents(const PassedEntity &, const ExprVisitor &) const
Walk non-deferred extent specification expressions of a dummy argument.
Definition: CallInterface.cpp:402
void walkDummyArgumentLengths(const PassedEntity &, const ExprVisitor &) const
Walk non-deferred length specification expressions of a dummy argument.
Definition: CallInterface.cpp:350
bool requireDispatchCall() const
Definition: CallInterface.cpp:91
const Fortran::evaluate::ProcedureDesignator * getIfIndirectCall() const
Definition: CallInterface.cpp:147
bool mustMapInterfaceSymbolsForDummyArgument(const PassedEntity &) const
Definition: CallInterface.cpp:429
const Fortran::semantics::Symbol * getProcedureSymbol() const
Definition: CallInterface.cpp:80
bool isIndirectCall() const
Definition: CallInterface.cpp:84
void placeInput(const PassedEntity &passedEntity, mlir::Value arg)
Definition: CallInterface.cpp:284
const Fortran::semantics::Symbol * getDummySymbol(const PassedEntity &entity) const
Definition: CallInterface.cpp:458
void walkResultExtents(const ExprVisitor &) const
Walk the result non-deferred extent specification expressions.
Definition: CallInterface.cpp:386
std::optional< unsigned > getPassArgIndex() const
Definition: CallInterface.cpp:113
mlir::Type getResultStorageType() const
Definition: CallInterface.cpp:475
const Fortran::semantics::Symbol & getResultSymbol() const
Definition: CallInterface.cpp:488
mlir::Value getArgumentValue(const semantics::Symbol &sym) const
Definition: CallInterface.cpp:440
void walkResultLengths(const ExprVisitor &) const
Walk the result non-deferred length specification expressions.
Definition: CallInterface.cpp:339
bool hasAlternateReturns() const
CRTP callbacks.
Definition: CallInterface.cpp:59
llvm::ArrayRef< mlir::Value > getInputs() const
Get the input vector once it is complete.
Definition: CallInterface.h:349
Definition: symbol.h:712
Definition: FIRType.h:77
Definition: OpenACC.h:20
Definition: AbstractConverter.h:59
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:1742
mlir::FunctionType translateSignature(const Fortran::evaluate::ProcedureDesignator &, Fortran::lower::AbstractConverter &)
Translate a procedure characteristics to an mlir::FunctionType signature.
Definition: CallInterface.cpp:1710
bool isCPtrArgByValueType(mlir::Type ty)
Definition: CallInterface.cpp:1764
mlir::func::FuncOp getOrDeclareFunction(const Fortran::evaluate::ProcedureDesignator &, Fortran::lower::AbstractConverter &)
Definition: CallInterface.cpp:1716
mlir::Type getUntypedBoxProcType(mlir::MLIRContext *context)
Return !fir.boxproc<() -> ()> type.
Definition: CallInterface.cpp:32
mlir::Type getDummyProcedureType(const Fortran::semantics::Symbol &dummyProc, Fortran::lower::AbstractConverter &)
Definition: CallInterface.cpp:1751
Definition: AbstractConverter.h:31
Definition: AbstractConverter.h:27
Definition: characteristics.h:282
Definition: characteristics.h:355
Definition: CallInterface.h:141
int passedEntityPosition
Definition: CallInterface.h:150
Property property
Definition: CallInterface.h:154
llvm::SmallVector< mlir::NamedAttribute > attributes
MLIR attributes for this argument.
Definition: CallInterface.h:156
mlir::Type type
Type for this input/output.
Definition: CallInterface.h:147
Definition: CallInterface.h:161
FortranEntity entity
Definition: CallInterface.h:192
bool testTKR(Fortran::common::IgnoreTKR flag) const
Does the argument have the specified IgnoreTKR flag?
Definition: CallInterface.cpp:1396
bool mayRequireIntentoutFinalization() const
Definition: CallInterface.cpp:1462
bool mayBeModifiedByCall() const
Can the argument be modified by the callee?
Definition: CallInterface.cpp:1380
bool mayBeReadByCall() const
Can the argument be read by the callee?
Definition: CallInterface.cpp:1389
bool hasValueAttribute() const
Does the dummy argument have the VALUE attribute?
Definition: CallInterface.cpp:1437
bool isIntentOut() const
Is the argument INTENT(OUT)
Definition: CallInterface.cpp:1409
bool hasAllocatableAttribute() const
Does the dummy argument have the ALLOCATABLE attribute?
Definition: CallInterface.cpp:1449
const Fortran::evaluate::characteristics::DummyArgument * characteristics
Pointer to the argument characteristics. Nullptr for results.
Definition: CallInterface.h:197
bool isSequenceAssociatedDescriptor() const
Definition: CallInterface.cpp:1501
PassEntityBy passBy
How entity is passed by.
Definition: CallInterface.h:188
bool mustBeMadeContiguous() const
Does the argument have the CONTIGUOUS attribute or have explicit shape?
Definition: CallInterface.cpp:1415
bool isOptional() const
Is the dummy argument optional?
Definition: CallInterface.cpp:1374
Definition: CallInterface.h:65
Definition: PFTBuilder.h:605