1 //===-- CallInterface.cpp -- Procedure call interface ---------------------===//
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 #include "flang/Lower/CallInterface.h"
10 #include "flang/Evaluate/fold.h"
11 #include "flang/Lower/Bridge.h"
12 #include "flang/Lower/Mangler.h"
13 #include "flang/Lower/PFTBuilder.h"
14 #include "flang/Lower/StatementContext.h"
15 #include "flang/Lower/Support/Utils.h"
16 #include "flang/Lower/Todo.h"
17 #include "flang/Optimizer/Builder/Character.h"
18 #include "flang/Optimizer/Builder/FIRBuilder.h"
19 #include "flang/Optimizer/Dialect/FIRDialect.h"
20 #include "flang/Optimizer/Dialect/FIROpsSupport.h"
21 #include "flang/Optimizer/Support/InternalNames.h"
22 #include "flang/Semantics/symbol.h"
23 #include "flang/Semantics/tools.h"
24 
25 //===----------------------------------------------------------------------===//
26 // BIND(C) mangling helpers
27 //===----------------------------------------------------------------------===//
28 
29 // Return the binding label (from BIND(C...)) or the mangled name of a symbol.
30 static std::string getMangledName(const Fortran::semantics::Symbol &symbol) {
31   const std::string *bindName = symbol.GetBindName();
32   return bindName ? *bindName : Fortran::lower::mangle::mangleName(symbol);
33 }
34 
35 /// Return the type of a dummy procedure given its characteristic (if it has
36 /// one).
37 mlir::Type getProcedureDesignatorType(
38     const Fortran::evaluate::characteristics::Procedure *,
39     Fortran::lower::AbstractConverter &converter) {
40   // TODO: Get actual function type of the dummy procedure, at least when an
41   // interface is given. The result type should be available even if the arity
42   // and type of the arguments is not.
43   llvm::SmallVector<mlir::Type> resultTys;
44   llvm::SmallVector<mlir::Type> inputTys;
45   // In general, that is a nice to have but we cannot guarantee to find the
46   // function type that will match the one of the calls, we may not even know
47   // how many arguments the dummy procedure accepts (e.g. if a procedure
48   // pointer is only transiting through the current procedure without being
49   // called), so a function type cast must always be inserted.
50   auto *context = &converter.getMLIRContext();
51   auto untypedFunc = mlir::FunctionType::get(context, inputTys, resultTys);
52   return fir::BoxProcType::get(context, untypedFunc);
53 }
54 
55 //===----------------------------------------------------------------------===//
56 // Caller side interface implementation
57 //===----------------------------------------------------------------------===//
58 
59 bool Fortran::lower::CallerInterface::hasAlternateReturns() const {
60   return procRef.hasAlternateReturns();
61 }
62 
63 std::string Fortran::lower::CallerInterface::getMangledName() const {
64   const Fortran::evaluate::ProcedureDesignator &proc = procRef.proc();
65   if (const Fortran::semantics::Symbol *symbol = proc.GetSymbol())
66     return ::getMangledName(symbol->GetUltimate());
67   assert(proc.GetSpecificIntrinsic() &&
68          "expected intrinsic procedure in designator");
69   return proc.GetName();
70 }
71 
72 const Fortran::semantics::Symbol *
73 Fortran::lower::CallerInterface::getProcedureSymbol() const {
74   return procRef.proc().GetSymbol();
75 }
76 
77 bool Fortran::lower::CallerInterface::isIndirectCall() const {
78   if (const Fortran::semantics::Symbol *symbol = procRef.proc().GetSymbol())
79     return Fortran::semantics::IsPointer(*symbol) ||
80            Fortran::semantics::IsDummy(*symbol);
81   return false;
82 }
83 
84 const Fortran::semantics::Symbol *
85 Fortran::lower::CallerInterface::getIfIndirectCallSymbol() const {
86   if (const Fortran::semantics::Symbol *symbol = procRef.proc().GetSymbol())
87     if (Fortran::semantics::IsPointer(*symbol) ||
88         Fortran::semantics::IsDummy(*symbol))
89       return symbol;
90   return nullptr;
91 }
92 
93 mlir::Location Fortran::lower::CallerInterface::getCalleeLocation() const {
94   const Fortran::evaluate::ProcedureDesignator &proc = procRef.proc();
95   // FIXME: If the callee is defined in the same file but after the current
96   // unit we cannot get its location here and the funcOp is created at the
97   // wrong location (i.e, the caller location).
98   if (const Fortran::semantics::Symbol *symbol = proc.GetSymbol())
99     return converter.genLocation(symbol->name());
100   // Use current location for intrinsics.
101   return converter.getCurrentLocation();
102 }
103 
104 // Get dummy argument characteristic for a procedure with implicit interface
105 // from the actual argument characteristic. The actual argument may not be a F77
106 // entity. The attribute must be dropped and the shape, if any, must be made
107 // explicit.
108 static Fortran::evaluate::characteristics::DummyDataObject
109 asImplicitArg(Fortran::evaluate::characteristics::DummyDataObject &&dummy) {
110   Fortran::evaluate::Shape shape =
111       dummy.type.attrs().none() ? dummy.type.shape()
112                                 : Fortran::evaluate::Shape(dummy.type.Rank());
113   return Fortran::evaluate::characteristics::DummyDataObject(
114       Fortran::evaluate::characteristics::TypeAndShape(dummy.type.type(),
115                                                        std::move(shape)));
116 }
117 
118 static Fortran::evaluate::characteristics::DummyArgument
119 asImplicitArg(Fortran::evaluate::characteristics::DummyArgument &&dummy) {
120   return std::visit(
121       Fortran::common::visitors{
122           [&](Fortran::evaluate::characteristics::DummyDataObject &obj) {
123             return Fortran::evaluate::characteristics::DummyArgument(
124                 std::move(dummy.name), asImplicitArg(std::move(obj)));
125           },
126           [&](Fortran::evaluate::characteristics::DummyProcedure &proc) {
127             return Fortran::evaluate::characteristics::DummyArgument(
128                 std::move(dummy.name), std::move(proc));
129           },
130           [](Fortran::evaluate::characteristics::AlternateReturn &x) {
131             return Fortran::evaluate::characteristics::DummyArgument(
132                 std::move(x));
133           }},
134       dummy.u);
135 }
136 
137 Fortran::evaluate::characteristics::Procedure
138 Fortran::lower::CallerInterface::characterize() const {
139   Fortran::evaluate::FoldingContext &foldingContext =
140       converter.getFoldingContext();
141   std::optional<Fortran::evaluate::characteristics::Procedure> characteristic =
142       Fortran::evaluate::characteristics::Procedure::Characterize(
143           procRef.proc(), foldingContext);
144   assert(characteristic && "Failed to get characteristic from procRef");
145   // The characteristic may not contain the argument characteristic if the
146   // ProcedureDesignator has no interface.
147   if (!characteristic->HasExplicitInterface()) {
148     for (const std::optional<Fortran::evaluate::ActualArgument> &arg :
149          procRef.arguments()) {
150       if (arg.value().isAlternateReturn()) {
151         characteristic->dummyArguments.emplace_back(
152             Fortran::evaluate::characteristics::AlternateReturn{});
153       } else {
154         // Argument cannot be optional with implicit interface
155         const Fortran::lower::SomeExpr *expr = arg.value().UnwrapExpr();
156         assert(
157             expr &&
158             "argument in call with implicit interface cannot be assumed type");
159         std::optional<Fortran::evaluate::characteristics::DummyArgument>
160             argCharacteristic =
161                 Fortran::evaluate::characteristics::DummyArgument::FromActual(
162                     "actual", *expr, foldingContext);
163         assert(argCharacteristic &&
164                "failed to characterize argument in implicit call");
165         characteristic->dummyArguments.emplace_back(
166             asImplicitArg(std::move(*argCharacteristic)));
167       }
168     }
169   }
170   return *characteristic;
171 }
172 
173 void Fortran::lower::CallerInterface::placeInput(
174     const PassedEntity &passedEntity, mlir::Value arg) {
175   assert(static_cast<int>(actualInputs.size()) > passedEntity.firArgument &&
176          passedEntity.firArgument >= 0 &&
177          passedEntity.passBy != CallInterface::PassEntityBy::AddressAndLength &&
178          "bad arg position");
179   actualInputs[passedEntity.firArgument] = arg;
180 }
181 
182 void Fortran::lower::CallerInterface::placeAddressAndLengthInput(
183     const PassedEntity &passedEntity, mlir::Value addr, mlir::Value len) {
184   assert(static_cast<int>(actualInputs.size()) > passedEntity.firArgument &&
185          static_cast<int>(actualInputs.size()) > passedEntity.firLength &&
186          passedEntity.firArgument >= 0 && passedEntity.firLength >= 0 &&
187          passedEntity.passBy == CallInterface::PassEntityBy::AddressAndLength &&
188          "bad arg position");
189   actualInputs[passedEntity.firArgument] = addr;
190   actualInputs[passedEntity.firLength] = len;
191 }
192 
193 bool Fortran::lower::CallerInterface::verifyActualInputs() const {
194   if (getNumFIRArguments() != actualInputs.size())
195     return false;
196   for (mlir::Value arg : actualInputs) {
197     if (!arg)
198       return false;
199   }
200   return true;
201 }
202 
203 void Fortran::lower::CallerInterface::walkResultLengths(
204     ExprVisitor visitor) const {
205   assert(characteristic && "characteristic was not computed");
206   const Fortran::evaluate::characteristics::FunctionResult &result =
207       characteristic->functionResult.value();
208   const Fortran::evaluate::characteristics::TypeAndShape *typeAndShape =
209       result.GetTypeAndShape();
210   assert(typeAndShape && "no result type");
211   Fortran::evaluate::DynamicType dynamicType = typeAndShape->type();
212   // Visit result length specification expressions that are explicit.
213   if (dynamicType.category() == Fortran::common::TypeCategory::Character) {
214     if (std::optional<Fortran::evaluate::ExtentExpr> length =
215             dynamicType.GetCharLength())
216       visitor(toEvExpr(*length));
217   } else if (dynamicType.category() == common::TypeCategory::Derived) {
218     const Fortran::semantics::DerivedTypeSpec &derivedTypeSpec =
219         dynamicType.GetDerivedTypeSpec();
220     if (Fortran::semantics::CountLenParameters(derivedTypeSpec) > 0)
221       TODO(converter.getCurrentLocation(),
222            "function result with derived type length parameters");
223   }
224 }
225 
226 // Compute extent expr from shapeSpec of an explicit shape.
227 // TODO: Allow evaluate shape analysis to work in a mode where it disregards
228 // the non-constant aspects when building the shape to avoid having this here.
229 static Fortran::evaluate::ExtentExpr
230 getExtentExpr(const Fortran::semantics::ShapeSpec &shapeSpec) {
231   const auto &ubound = shapeSpec.ubound().GetExplicit();
232   const auto &lbound = shapeSpec.lbound().GetExplicit();
233   assert(lbound && ubound && "shape must be explicit");
234   return Fortran::common::Clone(*ubound) - Fortran::common::Clone(*lbound) +
235          Fortran::evaluate::ExtentExpr{1};
236 }
237 
238 void Fortran::lower::CallerInterface::walkResultExtents(
239     ExprVisitor visitor) const {
240   // Walk directly the result symbol shape (the characteristic shape may contain
241   // descriptor inquiries to it that would fail to lower on the caller side).
242   const Fortran::semantics::SubprogramDetails *interfaceDetails =
243       getInterfaceDetails();
244   if (interfaceDetails) {
245     const Fortran::semantics::Symbol &result = interfaceDetails->result();
246     if (const auto *objectDetails =
247             result.detailsIf<Fortran::semantics::ObjectEntityDetails>())
248       if (objectDetails->shape().IsExplicitShape())
249         for (const Fortran::semantics::ShapeSpec &shapeSpec :
250              objectDetails->shape())
251           visitor(Fortran::evaluate::AsGenericExpr(getExtentExpr(shapeSpec)));
252   } else {
253     if (procRef.Rank() != 0)
254       fir::emitFatalError(
255           converter.getCurrentLocation(),
256           "only scalar functions may not have an interface symbol");
257   }
258 }
259 
260 bool Fortran::lower::CallerInterface::mustMapInterfaceSymbols() const {
261   assert(characteristic && "characteristic was not computed");
262   const std::optional<Fortran::evaluate::characteristics::FunctionResult>
263       &result = characteristic->functionResult;
264   if (!result || result->CanBeReturnedViaImplicitInterface() ||
265       !getInterfaceDetails())
266     return false;
267   bool allResultSpecExprConstant = true;
268   auto visitor = [&](const Fortran::lower::SomeExpr &e) {
269     allResultSpecExprConstant &= Fortran::evaluate::IsConstantExpr(e);
270   };
271   walkResultLengths(visitor);
272   walkResultExtents(visitor);
273   return !allResultSpecExprConstant;
274 }
275 
276 mlir::Value Fortran::lower::CallerInterface::getArgumentValue(
277     const semantics::Symbol &sym) const {
278   mlir::Location loc = converter.getCurrentLocation();
279   const Fortran::semantics::SubprogramDetails *ifaceDetails =
280       getInterfaceDetails();
281   if (!ifaceDetails)
282     fir::emitFatalError(
283         loc, "mapping actual and dummy arguments requires an interface");
284   const std::vector<Fortran::semantics::Symbol *> &dummies =
285       ifaceDetails->dummyArgs();
286   auto it = std::find(dummies.begin(), dummies.end(), &sym);
287   if (it == dummies.end())
288     fir::emitFatalError(loc, "symbol is not a dummy in this call");
289   FirValue mlirArgIndex = passedArguments[it - dummies.begin()].firArgument;
290   return actualInputs[mlirArgIndex];
291 }
292 
293 mlir::Type Fortran::lower::CallerInterface::getResultStorageType() const {
294   if (passedResult)
295     return fir::dyn_cast_ptrEleTy(inputs[passedResult->firArgument].type);
296   assert(saveResult && !outputs.empty());
297   return outputs[0].type;
298 }
299 
300 const Fortran::semantics::Symbol &
301 Fortran::lower::CallerInterface::getResultSymbol() const {
302   mlir::Location loc = converter.getCurrentLocation();
303   const Fortran::semantics::SubprogramDetails *ifaceDetails =
304       getInterfaceDetails();
305   if (!ifaceDetails)
306     fir::emitFatalError(
307         loc, "mapping actual and dummy arguments requires an interface");
308   return ifaceDetails->result();
309 }
310 
311 const Fortran::semantics::SubprogramDetails *
312 Fortran::lower::CallerInterface::getInterfaceDetails() const {
313   if (const Fortran::semantics::Symbol *iface =
314           procRef.proc().GetInterfaceSymbol())
315     return iface->GetUltimate()
316         .detailsIf<Fortran::semantics::SubprogramDetails>();
317   return nullptr;
318 }
319 
320 //===----------------------------------------------------------------------===//
321 // Callee side interface implementation
322 //===----------------------------------------------------------------------===//
323 
324 bool Fortran::lower::CalleeInterface::hasAlternateReturns() const {
325   return !funit.isMainProgram() &&
326          Fortran::semantics::HasAlternateReturns(funit.getSubprogramSymbol());
327 }
328 
329 std::string Fortran::lower::CalleeInterface::getMangledName() const {
330   if (funit.isMainProgram())
331     return fir::NameUniquer::doProgramEntry().str();
332   return ::getMangledName(funit.getSubprogramSymbol());
333 }
334 
335 const Fortran::semantics::Symbol *
336 Fortran::lower::CalleeInterface::getProcedureSymbol() const {
337   if (funit.isMainProgram())
338     return nullptr;
339   return &funit.getSubprogramSymbol();
340 }
341 
342 mlir::Location Fortran::lower::CalleeInterface::getCalleeLocation() const {
343   // FIXME: do NOT use unknown for the anonymous PROGRAM case. We probably
344   // should just stash the location in the funit regardless.
345   return converter.genLocation(funit.getStartingSourceLoc());
346 }
347 
348 Fortran::evaluate::characteristics::Procedure
349 Fortran::lower::CalleeInterface::characterize() const {
350   Fortran::evaluate::FoldingContext &foldingContext =
351       converter.getFoldingContext();
352   std::optional<Fortran::evaluate::characteristics::Procedure> characteristic =
353       Fortran::evaluate::characteristics::Procedure::Characterize(
354           funit.getSubprogramSymbol(), foldingContext);
355   assert(characteristic && "Fail to get characteristic from symbol");
356   return *characteristic;
357 }
358 
359 bool Fortran::lower::CalleeInterface::isMainProgram() const {
360   return funit.isMainProgram();
361 }
362 
363 mlir::FuncOp Fortran::lower::CalleeInterface::addEntryBlockAndMapArguments() {
364   // On the callee side, directly map the mlir::value argument of
365   // the function block to the Fortran symbols.
366   func.addEntryBlock();
367   mapPassedEntities();
368   return func;
369 }
370 
371 bool Fortran::lower::CalleeInterface::hasHostAssociated() const {
372   return funit.parentHasHostAssoc();
373 }
374 
375 mlir::Type Fortran::lower::CalleeInterface::getHostAssociatedTy() const {
376   assert(hasHostAssociated());
377   return funit.parentHostAssoc().getArgumentType(converter);
378 }
379 
380 mlir::Value Fortran::lower::CalleeInterface::getHostAssociatedTuple() const {
381   assert(hasHostAssociated() || !funit.getHostAssoc().empty());
382   return converter.hostAssocTupleValue();
383 }
384 
385 //===----------------------------------------------------------------------===//
386 // CallInterface implementation: this part is common to both caller and caller
387 // sides.
388 //===----------------------------------------------------------------------===//
389 
390 static void addSymbolAttribute(mlir::FuncOp func,
391                                const Fortran::semantics::Symbol &sym,
392                                mlir::MLIRContext &mlirContext) {
393   // Only add this on bind(C) functions for which the symbol is not reflected in
394   // the current context.
395   if (!Fortran::semantics::IsBindCProcedure(sym))
396     return;
397   std::string name =
398       Fortran::lower::mangle::mangleName(sym, /*keepExternalInScope=*/true);
399   func->setAttr(fir::getSymbolAttrName(),
400                 mlir::StringAttr::get(&mlirContext, name));
401 }
402 
403 /// Declare drives the different actions to be performed while analyzing the
404 /// signature and building/finding the mlir::FuncOp.
405 template <typename T>
406 void Fortran::lower::CallInterface<T>::declare() {
407   if (!side().isMainProgram()) {
408     characteristic.emplace(side().characterize());
409     bool isImplicit = characteristic->CanBeCalledViaImplicitInterface();
410     determineInterface(isImplicit, *characteristic);
411   }
412   // No input/output for main program
413 
414   // Create / get funcOp for direct calls. For indirect calls (only meaningful
415   // on the caller side), no funcOp has to be created here. The mlir::Value
416   // holding the indirection is used when creating the fir::CallOp.
417   if (!side().isIndirectCall()) {
418     std::string name = side().getMangledName();
419     mlir::ModuleOp module = converter.getModuleOp();
420     func = fir::FirOpBuilder::getNamedFunction(module, name);
421     if (!func) {
422       mlir::Location loc = side().getCalleeLocation();
423       mlir::FunctionType ty = genFunctionType();
424       func = fir::FirOpBuilder::createFunction(loc, module, name, ty);
425       if (const Fortran::semantics::Symbol *sym = side().getProcedureSymbol())
426         addSymbolAttribute(func, *sym, converter.getMLIRContext());
427       for (const auto &placeHolder : llvm::enumerate(inputs))
428         if (!placeHolder.value().attributes.empty())
429           func.setArgAttrs(placeHolder.index(), placeHolder.value().attributes);
430     }
431   }
432 }
433 
434 /// Once the signature has been analyzed and the mlir::FuncOp was built/found,
435 /// map the fir inputs to Fortran entities (the symbols or expressions).
436 template <typename T>
437 void Fortran::lower::CallInterface<T>::mapPassedEntities() {
438   // map back fir inputs to passed entities
439   if constexpr (std::is_same_v<T, Fortran::lower::CalleeInterface>) {
440     assert(inputs.size() == func.front().getArguments().size() &&
441            "function previously created with different number of arguments");
442     for (auto [fst, snd] : llvm::zip(inputs, func.front().getArguments()))
443       mapBackInputToPassedEntity(fst, snd);
444   } else {
445     // On the caller side, map the index of the mlir argument position
446     // to Fortran ActualArguments.
447     int firPosition = 0;
448     for (const FirPlaceHolder &placeHolder : inputs)
449       mapBackInputToPassedEntity(placeHolder, firPosition++);
450   }
451 }
452 
453 template <typename T>
454 void Fortran::lower::CallInterface<T>::mapBackInputToPassedEntity(
455     const FirPlaceHolder &placeHolder, FirValue firValue) {
456   PassedEntity &passedEntity =
457       placeHolder.passedEntityPosition == FirPlaceHolder::resultEntityPosition
458           ? passedResult.value()
459           : passedArguments[placeHolder.passedEntityPosition];
460   if (placeHolder.property == Property::CharLength)
461     passedEntity.firLength = firValue;
462   else
463     passedEntity.firArgument = firValue;
464 }
465 
466 /// Helpers to access ActualArgument/Symbols
467 static const Fortran::evaluate::ActualArguments &
468 getEntityContainer(const Fortran::evaluate::ProcedureRef &proc) {
469   return proc.arguments();
470 }
471 
472 static const std::vector<Fortran::semantics::Symbol *> &
473 getEntityContainer(Fortran::lower::pft::FunctionLikeUnit &funit) {
474   return funit.getSubprogramSymbol()
475       .get<Fortran::semantics::SubprogramDetails>()
476       .dummyArgs();
477 }
478 
479 static const Fortran::evaluate::ActualArgument *getDataObjectEntity(
480     const std::optional<Fortran::evaluate::ActualArgument> &arg) {
481   if (arg)
482     return &*arg;
483   return nullptr;
484 }
485 
486 static const Fortran::semantics::Symbol &
487 getDataObjectEntity(const Fortran::semantics::Symbol *arg) {
488   assert(arg && "expect symbol for data object entity");
489   return *arg;
490 }
491 
492 static const Fortran::evaluate::ActualArgument *
493 getResultEntity(const Fortran::evaluate::ProcedureRef &) {
494   return nullptr;
495 }
496 
497 static const Fortran::semantics::Symbol &
498 getResultEntity(Fortran::lower::pft::FunctionLikeUnit &funit) {
499   return funit.getSubprogramSymbol()
500       .get<Fortran::semantics::SubprogramDetails>()
501       .result();
502 }
503 
504 /// Bypass helpers to manipulate entities since they are not any symbol/actual
505 /// argument to associate. See SignatureBuilder below.
506 using FakeEntity = bool;
507 using FakeEntities = llvm::SmallVector<FakeEntity>;
508 static FakeEntities
509 getEntityContainer(const Fortran::evaluate::characteristics::Procedure &proc) {
510   FakeEntities enities(proc.dummyArguments.size());
511   return enities;
512 }
513 static const FakeEntity &getDataObjectEntity(const FakeEntity &e) { return e; }
514 static FakeEntity
515 getResultEntity(const Fortran::evaluate::characteristics::Procedure &proc) {
516   return false;
517 }
518 
519 /// This is the actual part that defines the FIR interface based on the
520 /// characteristic. It directly mutates the CallInterface members.
521 template <typename T>
522 class Fortran::lower::CallInterfaceImpl {
523   using CallInterface = Fortran::lower::CallInterface<T>;
524   using PassEntityBy = typename CallInterface::PassEntityBy;
525   using PassedEntity = typename CallInterface::PassedEntity;
526   using FirValue = typename CallInterface::FirValue;
527   using FortranEntity = typename CallInterface::FortranEntity;
528   using FirPlaceHolder = typename CallInterface::FirPlaceHolder;
529   using Property = typename CallInterface::Property;
530   using TypeAndShape = Fortran::evaluate::characteristics::TypeAndShape;
531   using DummyCharacteristics =
532       Fortran::evaluate::characteristics::DummyArgument;
533 
534 public:
535   CallInterfaceImpl(CallInterface &i)
536       : interface(i), mlirContext{i.converter.getMLIRContext()} {}
537 
538   void buildImplicitInterface(
539       const Fortran::evaluate::characteristics::Procedure &procedure) {
540     // Handle result
541     if (const std::optional<Fortran::evaluate::characteristics::FunctionResult>
542             &result = procedure.functionResult)
543       handleImplicitResult(*result);
544     else if (interface.side().hasAlternateReturns())
545       addFirResult(mlir::IndexType::get(&mlirContext),
546                    FirPlaceHolder::resultEntityPosition, Property::Value);
547     // Handle arguments
548     const auto &argumentEntities =
549         getEntityContainer(interface.side().getCallDescription());
550     for (auto pair : llvm::zip(procedure.dummyArguments, argumentEntities)) {
551       const Fortran::evaluate::characteristics::DummyArgument
552           &argCharacteristics = std::get<0>(pair);
553       std::visit(
554           Fortran::common::visitors{
555               [&](const auto &dummy) {
556                 const auto &entity = getDataObjectEntity(std::get<1>(pair));
557                 handleImplicitDummy(&argCharacteristics, dummy, entity);
558               },
559               [&](const Fortran::evaluate::characteristics::AlternateReturn &) {
560                 // nothing to do
561               },
562           },
563           argCharacteristics.u);
564     }
565   }
566 
567   void buildExplicitInterface(
568       const Fortran::evaluate::characteristics::Procedure &procedure) {
569     // Handle result
570     if (const std::optional<Fortran::evaluate::characteristics::FunctionResult>
571             &result = procedure.functionResult) {
572       if (result->CanBeReturnedViaImplicitInterface())
573         handleImplicitResult(*result);
574       else
575         handleExplicitResult(*result);
576     } else if (interface.side().hasAlternateReturns()) {
577       addFirResult(mlir::IndexType::get(&mlirContext),
578                    FirPlaceHolder::resultEntityPosition, Property::Value);
579     }
580     bool isBindC = procedure.IsBindC();
581     // Handle arguments
582     const auto &argumentEntities =
583         getEntityContainer(interface.side().getCallDescription());
584     for (auto pair : llvm::zip(procedure.dummyArguments, argumentEntities)) {
585       const Fortran::evaluate::characteristics::DummyArgument
586           &argCharacteristics = std::get<0>(pair);
587       std::visit(
588           Fortran::common::visitors{
589               [&](const Fortran::evaluate::characteristics::DummyDataObject
590                       &dummy) {
591                 const auto &entity = getDataObjectEntity(std::get<1>(pair));
592                 if (dummy.CanBePassedViaImplicitInterface())
593                   handleImplicitDummy(&argCharacteristics, dummy, entity);
594                 else
595                   handleExplicitDummy(&argCharacteristics, dummy, entity,
596                                       isBindC);
597               },
598               [&](const Fortran::evaluate::characteristics::DummyProcedure
599                       &dummy) {
600                 const auto &entity = getDataObjectEntity(std::get<1>(pair));
601                 handleImplicitDummy(&argCharacteristics, dummy, entity);
602               },
603               [&](const Fortran::evaluate::characteristics::AlternateReturn &) {
604                 // nothing to do
605               },
606           },
607           argCharacteristics.u);
608     }
609   }
610 
611   void appendHostAssocTupleArg(mlir::Type tupTy) {
612     mlir::MLIRContext *ctxt = tupTy.getContext();
613     addFirOperand(tupTy, nextPassedArgPosition(), Property::BaseAddress,
614                   {mlir::NamedAttribute{
615                       mlir::StringAttr::get(ctxt, fir::getHostAssocAttrName()),
616                       mlir::UnitAttr::get(ctxt)}});
617     interface.passedArguments.emplace_back(
618         PassedEntity{PassEntityBy::BaseAddress, std::nullopt,
619                      interface.side().getHostAssociatedTuple(), emptyValue()});
620   }
621 
622   static llvm::Optional<Fortran::evaluate::DynamicType> getResultDynamicType(
623       const Fortran::evaluate::characteristics::Procedure &procedure) {
624     if (const std::optional<Fortran::evaluate::characteristics::FunctionResult>
625             &result = procedure.functionResult)
626       if (const auto *resultTypeAndShape = result->GetTypeAndShape())
627         return resultTypeAndShape->type();
628     return llvm::None;
629   }
630 
631   static bool mustPassLengthWithDummyProcedure(
632       const Fortran::evaluate::characteristics::Procedure &procedure) {
633     // When passing a character function designator `bar` as dummy procedure to
634     // `foo` (e.g. `foo(bar)`), pass the result length of `bar` to `foo` so that
635     // `bar` can be called inside `foo` even if its length is assumed there.
636     // From an ABI perspective, the extra length argument must be handled
637     // exactly as if passing a character object. Using an argument of
638     // fir.boxchar type gives the expected behavior: after codegen, the
639     // fir.boxchar lengths are added after all the arguments as extra value
640     // arguments (the extra arguments order is the order of the fir.boxchar).
641 
642     // This ABI is compatible with ifort, nag, nvfortran, and xlf, but not
643     // gfortran. Gfortran does not pass the length and is therefore unable to
644     // handle later call to `bar` in `foo` where the length would be assumed. If
645     // the result is an array, nag and ifort and xlf still pass the length, but
646     // not nvfortran (and gfortran). It is not clear it is possible to call an
647     // array function with assumed length (f18 forbides defining such
648     // interfaces). Hence, passing the length is most likely useless, but stick
649     // with ifort/nag/xlf interface here.
650     if (llvm::Optional<Fortran::evaluate::DynamicType> type =
651             getResultDynamicType(procedure))
652       return type->category() == Fortran::common::TypeCategory::Character;
653     return false;
654   }
655 
656 private:
657   void handleImplicitResult(
658       const Fortran::evaluate::characteristics::FunctionResult &result) {
659     if (result.IsProcedurePointer())
660       TODO(interface.converter.getCurrentLocation(),
661            "procedure pointer result not yet handled");
662     const Fortran::evaluate::characteristics::TypeAndShape *typeAndShape =
663         result.GetTypeAndShape();
664     assert(typeAndShape && "expect type for non proc pointer result");
665     Fortran::evaluate::DynamicType dynamicType = typeAndShape->type();
666     // Character result allocated by caller and passed as hidden arguments
667     if (dynamicType.category() == Fortran::common::TypeCategory::Character) {
668       handleImplicitCharacterResult(dynamicType);
669     } else if (dynamicType.category() ==
670                Fortran::common::TypeCategory::Derived) {
671       // Derived result need to be allocated by the caller and the result value
672       // must be saved. Derived type in implicit interface cannot have length
673       // parameters.
674       setSaveResult();
675       mlir::Type mlirType = translateDynamicType(dynamicType);
676       addFirResult(mlirType, FirPlaceHolder::resultEntityPosition,
677                    Property::Value);
678     } else {
679       // All result other than characters/derived are simply returned by value
680       // in implicit interfaces
681       mlir::Type mlirType =
682           getConverter().genType(dynamicType.category(), dynamicType.kind());
683       addFirResult(mlirType, FirPlaceHolder::resultEntityPosition,
684                    Property::Value);
685     }
686   }
687   void
688   handleImplicitCharacterResult(const Fortran::evaluate::DynamicType &type) {
689     int resultPosition = FirPlaceHolder::resultEntityPosition;
690     setPassedResult(PassEntityBy::AddressAndLength,
691                     getResultEntity(interface.side().getCallDescription()));
692     mlir::Type lenTy = mlir::IndexType::get(&mlirContext);
693     std::optional<std::int64_t> constantLen = type.knownLength();
694     fir::CharacterType::LenType len =
695         constantLen ? *constantLen : fir::CharacterType::unknownLen();
696     mlir::Type charRefTy = fir::ReferenceType::get(
697         fir::CharacterType::get(&mlirContext, type.kind(), len));
698     mlir::Type boxCharTy = fir::BoxCharType::get(&mlirContext, type.kind());
699     addFirOperand(charRefTy, resultPosition, Property::CharAddress);
700     addFirOperand(lenTy, resultPosition, Property::CharLength);
701     /// For now, also return it by boxchar
702     addFirResult(boxCharTy, resultPosition, Property::BoxChar);
703   }
704 
705   /// Return a vector with an attribute with the name of the argument if this
706   /// is a callee interface and the name is available. Otherwise, just return
707   /// an empty vector.
708   llvm::SmallVector<mlir::NamedAttribute>
709   dummyNameAttr(const FortranEntity &entity) {
710     if constexpr (std::is_same_v<FortranEntity,
711                                  std::optional<Fortran::common::Reference<
712                                      const Fortran::semantics::Symbol>>>) {
713       if (entity.has_value()) {
714         const Fortran::semantics::Symbol *argument = &*entity.value();
715         // "fir.bindc_name" is used for arguments for the sake of consistency
716         // with other attributes carrying surface syntax names in FIR.
717         return {mlir::NamedAttribute(
718             mlir::StringAttr::get(&mlirContext, "fir.bindc_name"),
719             mlir::StringAttr::get(&mlirContext,
720                                   toStringRef(argument->name())))};
721       }
722     }
723     return {};
724   }
725 
726   void handleImplicitDummy(
727       const DummyCharacteristics *characteristics,
728       const Fortran::evaluate::characteristics::DummyDataObject &obj,
729       const FortranEntity &entity) {
730     Fortran::evaluate::DynamicType dynamicType = obj.type.type();
731     if (dynamicType.category() == Fortran::common::TypeCategory::Character) {
732       mlir::Type boxCharTy =
733           fir::BoxCharType::get(&mlirContext, dynamicType.kind());
734       addFirOperand(boxCharTy, nextPassedArgPosition(), Property::BoxChar,
735                     dummyNameAttr(entity));
736       addPassedArg(PassEntityBy::BoxChar, entity, characteristics);
737     } else {
738       // non-PDT derived type allowed in implicit interface.
739       mlir::Type type = translateDynamicType(dynamicType);
740       fir::SequenceType::Shape bounds = getBounds(obj.type.shape());
741       if (!bounds.empty())
742         type = fir::SequenceType::get(bounds, type);
743       mlir::Type refType = fir::ReferenceType::get(type);
744       addFirOperand(refType, nextPassedArgPosition(), Property::BaseAddress,
745                     dummyNameAttr(entity));
746       addPassedArg(PassEntityBy::BaseAddress, entity, characteristics);
747     }
748   }
749 
750   // Define when an explicit argument must be passed in a fir.box.
751   bool dummyRequiresBox(
752       const Fortran::evaluate::characteristics::DummyDataObject &obj) {
753     using ShapeAttr = Fortran::evaluate::characteristics::TypeAndShape::Attr;
754     using ShapeAttrs = Fortran::evaluate::characteristics::TypeAndShape::Attrs;
755     constexpr ShapeAttrs shapeRequiringBox = {
756         ShapeAttr::AssumedShape, ShapeAttr::DeferredShape,
757         ShapeAttr::AssumedRank, ShapeAttr::Coarray};
758     if ((obj.type.attrs() & shapeRequiringBox).any())
759       // Need to pass shape/coshape info in fir.box.
760       return true;
761     if (obj.type.type().IsPolymorphic())
762       // Need to pass dynamic type info in fir.box.
763       return true;
764     if (const Fortran::semantics::DerivedTypeSpec *derived =
765             Fortran::evaluate::GetDerivedTypeSpec(obj.type.type()))
766       // Need to pass type parameters in fir.box if any.
767       return derived->parameters().empty();
768     return false;
769   }
770 
771   mlir::Type
772   translateDynamicType(const Fortran::evaluate::DynamicType &dynamicType) {
773     Fortran::common::TypeCategory cat = dynamicType.category();
774     // DERIVED
775     if (cat == Fortran::common::TypeCategory::Derived) {
776       if (dynamicType.IsPolymorphic())
777         TODO(interface.converter.getCurrentLocation(),
778              "[translateDynamicType] polymorphic types");
779       return getConverter().genType(dynamicType.GetDerivedTypeSpec());
780     }
781     // CHARACTER with compile time constant length.
782     if (cat == Fortran::common::TypeCategory::Character)
783       if (std::optional<std::int64_t> constantLen =
784               toInt64(dynamicType.GetCharLength()))
785         return getConverter().genType(cat, dynamicType.kind(), {*constantLen});
786     // INTEGER, REAL, LOGICAL, COMPLEX, and CHARACTER with dynamic length.
787     return getConverter().genType(cat, dynamicType.kind());
788   }
789 
790   void handleExplicitDummy(
791       const DummyCharacteristics *characteristics,
792       const Fortran::evaluate::characteristics::DummyDataObject &obj,
793       const FortranEntity &entity, bool isBindC) {
794     using Attrs = Fortran::evaluate::characteristics::DummyDataObject::Attr;
795 
796     bool isValueAttr = false;
797     [[maybe_unused]] mlir::Location loc =
798         interface.converter.getCurrentLocation();
799     llvm::SmallVector<mlir::NamedAttribute> attrs = dummyNameAttr(entity);
800     auto addMLIRAttr = [&](llvm::StringRef attr) {
801       attrs.emplace_back(mlir::StringAttr::get(&mlirContext, attr),
802                          mlir::UnitAttr::get(&mlirContext));
803     };
804     if (obj.attrs.test(Attrs::Optional))
805       addMLIRAttr(fir::getOptionalAttrName());
806     if (obj.attrs.test(Attrs::Asynchronous))
807       TODO(loc, "Asynchronous in procedure interface");
808     if (obj.attrs.test(Attrs::Contiguous))
809       addMLIRAttr(fir::getContiguousAttrName());
810     if (obj.attrs.test(Attrs::Value))
811       isValueAttr = true; // TODO: do we want an mlir::Attribute as well?
812     if (obj.attrs.test(Attrs::Volatile))
813       TODO(loc, "Volatile in procedure interface");
814     if (obj.attrs.test(Attrs::Target))
815       addMLIRAttr(fir::getTargetAttrName());
816 
817     // TODO: intents that require special care (e.g finalization)
818 
819     using ShapeAttr = Fortran::evaluate::characteristics::TypeAndShape::Attr;
820     const Fortran::evaluate::characteristics::TypeAndShape::Attrs &shapeAttrs =
821         obj.type.attrs();
822     if (shapeAttrs.test(ShapeAttr::AssumedRank))
823       TODO(loc, "Assumed Rank in procedure interface");
824     if (shapeAttrs.test(ShapeAttr::Coarray))
825       TODO(loc, "Coarray in procedure interface");
826 
827     // So far assume that if the argument cannot be passed by implicit interface
828     // it must be by box. That may no be always true (e.g for simple optionals)
829 
830     Fortran::evaluate::DynamicType dynamicType = obj.type.type();
831     mlir::Type type = translateDynamicType(dynamicType);
832     fir::SequenceType::Shape bounds = getBounds(obj.type.shape());
833     if (!bounds.empty())
834       type = fir::SequenceType::get(bounds, type);
835     if (obj.attrs.test(Attrs::Allocatable))
836       type = fir::HeapType::get(type);
837     if (obj.attrs.test(Attrs::Pointer))
838       type = fir::PointerType::get(type);
839     mlir::Type boxType = fir::BoxType::get(type);
840 
841     if (obj.attrs.test(Attrs::Allocatable) || obj.attrs.test(Attrs::Pointer)) {
842       // Pass as fir.ref<fir.box>
843       mlir::Type boxRefType = fir::ReferenceType::get(boxType);
844       addFirOperand(boxRefType, nextPassedArgPosition(), Property::MutableBox,
845                     attrs);
846       addPassedArg(PassEntityBy::MutableBox, entity, characteristics);
847     } else if (dummyRequiresBox(obj)) {
848       // Pass as fir.box
849       if (isValueAttr)
850         TODO(loc, "assumed shape dummy argument with VALUE attribute");
851       addFirOperand(boxType, nextPassedArgPosition(), Property::Box, attrs);
852       addPassedArg(PassEntityBy::Box, entity, characteristics);
853     } else if (dynamicType.category() ==
854                Fortran::common::TypeCategory::Character) {
855       // Pass as fir.box_char
856       mlir::Type boxCharTy =
857           fir::BoxCharType::get(&mlirContext, dynamicType.kind());
858       addFirOperand(boxCharTy, nextPassedArgPosition(), Property::BoxChar,
859                     attrs);
860       addPassedArg(isValueAttr ? PassEntityBy::CharBoxValueAttribute
861                                : PassEntityBy::BoxChar,
862                    entity, characteristics);
863     } else {
864       // Pass as fir.ref unless it's by VALUE and BIND(C)
865       mlir::Type passType = fir::ReferenceType::get(type);
866       PassEntityBy passBy = PassEntityBy::BaseAddress;
867       Property prop = Property::BaseAddress;
868       if (isValueAttr) {
869         if (isBindC) {
870           passBy = PassEntityBy::Value;
871           prop = Property::Value;
872           passType = type;
873         } else {
874           passBy = PassEntityBy::BaseAddressValueAttribute;
875         }
876       }
877       addFirOperand(passType, nextPassedArgPosition(), prop, attrs);
878       addPassedArg(passBy, entity, characteristics);
879     }
880   }
881 
882   void handleImplicitDummy(
883       const DummyCharacteristics *characteristics,
884       const Fortran::evaluate::characteristics::DummyProcedure &proc,
885       const FortranEntity &entity) {
886     if (proc.attrs.test(
887             Fortran::evaluate::characteristics::DummyProcedure::Attr::Pointer))
888       TODO(interface.converter.getCurrentLocation(),
889            "procedure pointer arguments");
890     // Otherwise, it is a dummy procedure.
891     const Fortran::evaluate::characteristics::Procedure &procedure =
892         proc.procedure.value();
893     mlir::Type funcType =
894         getProcedureDesignatorType(&procedure, interface.converter);
895     llvm::Optional<Fortran::evaluate::DynamicType> resultTy =
896         getResultDynamicType(procedure);
897     if (resultTy && mustPassLengthWithDummyProcedure(procedure)) {
898       // The result length of dummy procedures that are character functions must
899       // be passed so that the dummy procedure can be called if it has assumed
900       // length on the callee side.
901       mlir::Type tupleType =
902           fir::factory::getCharacterProcedureTupleType(funcType);
903       llvm::StringRef charProcAttr = fir::getCharacterProcedureDummyAttrName();
904       addFirOperand(tupleType, nextPassedArgPosition(), Property::CharProcTuple,
905                     {mlir::NamedAttribute{
906                         mlir::StringAttr::get(&mlirContext, charProcAttr),
907                         mlir::UnitAttr::get(&mlirContext)}});
908       addPassedArg(PassEntityBy::CharProcTuple, entity, characteristics);
909       return;
910     }
911     addFirOperand(funcType, nextPassedArgPosition(), Property::BaseAddress);
912     addPassedArg(PassEntityBy::BaseAddress, entity, characteristics);
913   }
914 
915   void handleExplicitResult(
916       const Fortran::evaluate::characteristics::FunctionResult &result) {
917     using Attr = Fortran::evaluate::characteristics::FunctionResult::Attr;
918 
919     if (result.IsProcedurePointer())
920       TODO(interface.converter.getCurrentLocation(),
921            "procedure pointer results");
922     const Fortran::evaluate::characteristics::TypeAndShape *typeAndShape =
923         result.GetTypeAndShape();
924     assert(typeAndShape && "expect type for non proc pointer result");
925     mlir::Type mlirType = translateDynamicType(typeAndShape->type());
926     fir::SequenceType::Shape bounds = getBounds(typeAndShape->shape());
927     if (!bounds.empty())
928       mlirType = fir::SequenceType::get(bounds, mlirType);
929     if (result.attrs.test(Attr::Allocatable))
930       mlirType = fir::BoxType::get(fir::HeapType::get(mlirType));
931     if (result.attrs.test(Attr::Pointer))
932       mlirType = fir::BoxType::get(fir::PointerType::get(mlirType));
933 
934     if (fir::isa_char(mlirType)) {
935       // Character scalar results must be passed as arguments in lowering so
936       // that an assumed length character function callee can access the result
937       // length. A function with a result requiring an explicit interface does
938       // not have to be compatible with assumed length function, but most
939       // compilers supports it.
940       handleImplicitCharacterResult(typeAndShape->type());
941       return;
942     }
943 
944     addFirResult(mlirType, FirPlaceHolder::resultEntityPosition,
945                  Property::Value);
946     // Explicit results require the caller to allocate the storage and save the
947     // function result in the storage with a fir.save_result.
948     setSaveResult();
949   }
950 
951   fir::SequenceType::Shape getBounds(const Fortran::evaluate::Shape &shape) {
952     fir::SequenceType::Shape bounds;
953     for (const std::optional<Fortran::evaluate::ExtentExpr> &extent : shape) {
954       fir::SequenceType::Extent bound = fir::SequenceType::getUnknownExtent();
955       if (std::optional<std::int64_t> i = toInt64(extent))
956         bound = *i;
957       bounds.emplace_back(bound);
958     }
959     return bounds;
960   }
961   std::optional<std::int64_t>
962   toInt64(std::optional<
963           Fortran::evaluate::Expr<Fortran::evaluate::SubscriptInteger>>
964               expr) {
965     if (expr)
966       return Fortran::evaluate::ToInt64(Fortran::evaluate::Fold(
967           getConverter().getFoldingContext(), toEvExpr(*expr)));
968     return std::nullopt;
969   }
970   void
971   addFirOperand(mlir::Type type, int entityPosition, Property p,
972                 llvm::ArrayRef<mlir::NamedAttribute> attributes = llvm::None) {
973     interface.inputs.emplace_back(
974         FirPlaceHolder{type, entityPosition, p, attributes});
975   }
976   void
977   addFirResult(mlir::Type type, int entityPosition, Property p,
978                llvm::ArrayRef<mlir::NamedAttribute> attributes = llvm::None) {
979     interface.outputs.emplace_back(
980         FirPlaceHolder{type, entityPosition, p, attributes});
981   }
982   void addPassedArg(PassEntityBy p, FortranEntity entity,
983                     const DummyCharacteristics *characteristics) {
984     interface.passedArguments.emplace_back(
985         PassedEntity{p, entity, emptyValue(), emptyValue(), characteristics});
986   }
987   void setPassedResult(PassEntityBy p, FortranEntity entity) {
988     interface.passedResult =
989         PassedEntity{p, entity, emptyValue(), emptyValue()};
990   }
991   void setSaveResult() { interface.saveResult = true; }
992   int nextPassedArgPosition() { return interface.passedArguments.size(); }
993 
994   static FirValue emptyValue() {
995     if constexpr (std::is_same_v<Fortran::lower::CalleeInterface, T>) {
996       return {};
997     } else {
998       return -1;
999     }
1000   }
1001 
1002   Fortran::lower::AbstractConverter &getConverter() {
1003     return interface.converter;
1004   }
1005   CallInterface &interface;
1006   mlir::MLIRContext &mlirContext;
1007 };
1008 
1009 template <typename T>
1010 bool Fortran::lower::CallInterface<T>::PassedEntity::isOptional() const {
1011   if (!characteristics)
1012     return false;
1013   return characteristics->IsOptional();
1014 }
1015 template <typename T>
1016 bool Fortran::lower::CallInterface<T>::PassedEntity::mayBeModifiedByCall()
1017     const {
1018   if (!characteristics)
1019     return true;
1020   return characteristics->GetIntent() != Fortran::common::Intent::In;
1021 }
1022 template <typename T>
1023 bool Fortran::lower::CallInterface<T>::PassedEntity::mayBeReadByCall() const {
1024   if (!characteristics)
1025     return true;
1026   return characteristics->GetIntent() != Fortran::common::Intent::Out;
1027 }
1028 
1029 template <typename T>
1030 void Fortran::lower::CallInterface<T>::determineInterface(
1031     bool isImplicit,
1032     const Fortran::evaluate::characteristics::Procedure &procedure) {
1033   CallInterfaceImpl<T> impl(*this);
1034   if (isImplicit)
1035     impl.buildImplicitInterface(procedure);
1036   else
1037     impl.buildExplicitInterface(procedure);
1038   // We only expect the extra host asspciations argument from the callee side as
1039   // the definition of internal procedures will be present, and we'll always
1040   // have a FuncOp definition in the ModuleOp, when lowering.
1041   if constexpr (std::is_same_v<T, Fortran::lower::CalleeInterface>) {
1042     if (side().hasHostAssociated())
1043       impl.appendHostAssocTupleArg(side().getHostAssociatedTy());
1044   }
1045 }
1046 
1047 template <typename T>
1048 mlir::FunctionType Fortran::lower::CallInterface<T>::genFunctionType() {
1049   llvm::SmallVector<mlir::Type> returnTys;
1050   llvm::SmallVector<mlir::Type> inputTys;
1051   for (const FirPlaceHolder &placeHolder : outputs)
1052     returnTys.emplace_back(placeHolder.type);
1053   for (const FirPlaceHolder &placeHolder : inputs)
1054     inputTys.emplace_back(placeHolder.type);
1055   return mlir::FunctionType::get(&converter.getMLIRContext(), inputTys,
1056                                  returnTys);
1057 }
1058 
1059 template <typename T>
1060 llvm::SmallVector<mlir::Type>
1061 Fortran::lower::CallInterface<T>::getResultType() const {
1062   llvm::SmallVector<mlir::Type> types;
1063   for (const FirPlaceHolder &out : outputs)
1064     types.emplace_back(out.type);
1065   return types;
1066 }
1067 
1068 template class Fortran::lower::CallInterface<Fortran::lower::CalleeInterface>;
1069 template class Fortran::lower::CallInterface<Fortran::lower::CallerInterface>;
1070 
1071 //===----------------------------------------------------------------------===//
1072 // Function Type Translation
1073 //===----------------------------------------------------------------------===//
1074 
1075 /// Build signature from characteristics when there is no Fortran entity to
1076 /// associate with the arguments (i.e, this is not a call site or a procedure
1077 /// declaration. This is needed when dealing with function pointers/dummy
1078 /// arguments.
1079 
1080 class SignatureBuilder;
1081 template <>
1082 struct Fortran::lower::PassedEntityTypes<SignatureBuilder> {
1083   using FortranEntity = FakeEntity;
1084   using FirValue = int;
1085 };
1086 
1087 /// SignatureBuilder is a CRTP implementation of CallInterface intended to
1088 /// help translating characteristics::Procedure to mlir::FunctionType using
1089 /// the CallInterface translation.
1090 class SignatureBuilder
1091     : public Fortran::lower::CallInterface<SignatureBuilder> {
1092 public:
1093   SignatureBuilder(const Fortran::evaluate::characteristics::Procedure &p,
1094                    Fortran::lower::AbstractConverter &c, bool forceImplicit)
1095       : CallInterface{c}, proc{p} {
1096     bool isImplicit = forceImplicit || proc.CanBeCalledViaImplicitInterface();
1097     determineInterface(isImplicit, proc);
1098   }
1099   /// Does the procedure characteristics being translated have alternate
1100   /// returns ?
1101   bool hasAlternateReturns() const {
1102     for (const Fortran::evaluate::characteristics::DummyArgument &dummy :
1103          proc.dummyArguments)
1104       if (std::holds_alternative<
1105               Fortran::evaluate::characteristics::AlternateReturn>(dummy.u))
1106         return true;
1107     return false;
1108   };
1109 
1110   /// This is only here to fulfill CRTP dependencies and should not be called.
1111   std::string getMangledName() const {
1112     llvm_unreachable("trying to get name from SignatureBuilder");
1113   }
1114 
1115   /// This is only here to fulfill CRTP dependencies and should not be called.
1116   mlir::Location getCalleeLocation() const {
1117     llvm_unreachable("trying to get callee location from SignatureBuilder");
1118   }
1119 
1120   /// This is only here to fulfill CRTP dependencies and should not be called.
1121   const Fortran::semantics::Symbol *getProcedureSymbol() const {
1122     llvm_unreachable("trying to get callee symbol from SignatureBuilder");
1123   };
1124 
1125   Fortran::evaluate::characteristics::Procedure characterize() const {
1126     return proc;
1127   }
1128   /// SignatureBuilder cannot be used on main program.
1129   static constexpr bool isMainProgram() { return false; }
1130 
1131   /// Return the characteristics::Procedure that is being translated to
1132   /// mlir::FunctionType.
1133   const Fortran::evaluate::characteristics::Procedure &
1134   getCallDescription() const {
1135     return proc;
1136   }
1137 
1138   /// This is not the description of an indirect call.
1139   static constexpr bool isIndirectCall() { return false; }
1140 
1141   /// Return the translated signature.
1142   mlir::FunctionType getFunctionType() { return genFunctionType(); }
1143 
1144   // Copy of base implementation.
1145   static constexpr bool hasHostAssociated() { return false; }
1146   mlir::Type getHostAssociatedTy() const {
1147     llvm_unreachable("getting host associated type in SignatureBuilder");
1148   }
1149 
1150 private:
1151   const Fortran::evaluate::characteristics::Procedure &proc;
1152 };
1153 
1154 mlir::FunctionType Fortran::lower::translateSignature(
1155     const Fortran::evaluate::ProcedureDesignator &proc,
1156     Fortran::lower::AbstractConverter &converter) {
1157   std::optional<Fortran::evaluate::characteristics::Procedure> characteristics =
1158       Fortran::evaluate::characteristics::Procedure::Characterize(
1159           proc, converter.getFoldingContext());
1160   // Most unrestricted intrinsic characteristic has the Elemental attribute
1161   // which triggers CanBeCalledViaImplicitInterface to return false. However,
1162   // using implicit interface rules is just fine here.
1163   bool forceImplicit = proc.GetSpecificIntrinsic();
1164   return SignatureBuilder{characteristics.value(), converter, forceImplicit}
1165       .getFunctionType();
1166 }
1167 
1168 mlir::FuncOp Fortran::lower::getOrDeclareFunction(
1169     llvm::StringRef name, const Fortran::evaluate::ProcedureDesignator &proc,
1170     Fortran::lower::AbstractConverter &converter) {
1171   mlir::ModuleOp module = converter.getModuleOp();
1172   mlir::FuncOp func = fir::FirOpBuilder::getNamedFunction(module, name);
1173   if (func)
1174     return func;
1175 
1176   const Fortran::semantics::Symbol *symbol = proc.GetSymbol();
1177   assert(symbol && "non user function in getOrDeclareFunction");
1178   // getOrDeclareFunction is only used for functions not defined in the current
1179   // program unit, so use the location of the procedure designator symbol, which
1180   // is the first occurrence of the procedure in the program unit.
1181   mlir::Location loc = converter.genLocation(symbol->name());
1182   std::optional<Fortran::evaluate::characteristics::Procedure> characteristics =
1183       Fortran::evaluate::characteristics::Procedure::Characterize(
1184           proc, converter.getFoldingContext());
1185   mlir::FunctionType ty = SignatureBuilder{characteristics.value(), converter,
1186                                            /*forceImplicit=*/false}
1187                               .getFunctionType();
1188   mlir::FuncOp newFunc =
1189       fir::FirOpBuilder::createFunction(loc, module, name, ty);
1190   addSymbolAttribute(newFunc, *symbol, converter.getMLIRContext());
1191   return newFunc;
1192 }
1193 
1194 // Is it required to pass a dummy procedure with \p characteristics as a tuple
1195 // containing the function address and the result length ?
1196 static bool mustPassLengthWithDummyProcedure(
1197     const std::optional<Fortran::evaluate::characteristics::Procedure>
1198         &characteristics) {
1199   return characteristics &&
1200          Fortran::lower::CallInterfaceImpl<SignatureBuilder>::
1201              mustPassLengthWithDummyProcedure(*characteristics);
1202 }
1203 
1204 bool Fortran::lower::mustPassLengthWithDummyProcedure(
1205     const Fortran::evaluate::ProcedureDesignator &procedure,
1206     Fortran::lower::AbstractConverter &converter) {
1207   std::optional<Fortran::evaluate::characteristics::Procedure> characteristics =
1208       Fortran::evaluate::characteristics::Procedure::Characterize(
1209           procedure, converter.getFoldingContext());
1210   return ::mustPassLengthWithDummyProcedure(characteristics);
1211 }
1212 
1213 mlir::Type Fortran::lower::getDummyProcedureType(
1214     const Fortran::semantics::Symbol &dummyProc,
1215     Fortran::lower::AbstractConverter &converter) {
1216   std::optional<Fortran::evaluate::characteristics::Procedure> iface =
1217       Fortran::evaluate::characteristics::Procedure::Characterize(
1218           dummyProc, converter.getFoldingContext());
1219   mlir::Type procType = getProcedureDesignatorType(
1220       iface.has_value() ? &*iface : nullptr, converter);
1221   if (::mustPassLengthWithDummyProcedure(iface))
1222     return fir::factory::getCharacterProcedureTupleType(procType);
1223   return procType;
1224 }
1225