xref: /llvm-project/flang/lib/Lower/CallInterface.cpp (revision d732c86c928271cf3a829d95a1fcc560894ab8e4)
1e1a12767SValentin Clement //===-- CallInterface.cpp -- Procedure call interface ---------------------===//
2e1a12767SValentin Clement //
3e1a12767SValentin Clement // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4e1a12767SValentin Clement // See https://llvm.org/LICENSE.txt for license information.
5e1a12767SValentin Clement // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6e1a12767SValentin Clement //
7e1a12767SValentin Clement //===----------------------------------------------------------------------===//
8e1a12767SValentin Clement 
9e1a12767SValentin Clement #include "flang/Lower/CallInterface.h"
1078145a6bSValentin Clement (バレンタイン クレメン) #include "flang/Common/Fortran.h"
11e1a12767SValentin Clement #include "flang/Evaluate/fold.h"
12e1a12767SValentin Clement #include "flang/Lower/Bridge.h"
13e1a12767SValentin Clement #include "flang/Lower/Mangler.h"
14e1a12767SValentin Clement #include "flang/Lower/PFTBuilder.h"
15764f95a8SValentin Clement #include "flang/Lower/StatementContext.h"
16e1a12767SValentin Clement #include "flang/Lower/Support/Utils.h"
17764f95a8SValentin Clement #include "flang/Optimizer/Builder/Character.h"
18e1a12767SValentin Clement #include "flang/Optimizer/Builder/FIRBuilder.h"
195b66cc10SValentin Clement #include "flang/Optimizer/Builder/Todo.h"
20e1a12767SValentin Clement #include "flang/Optimizer/Dialect/FIRDialect.h"
21e1a12767SValentin Clement #include "flang/Optimizer/Dialect/FIROpsSupport.h"
22e1a12767SValentin Clement #include "flang/Optimizer/Support/InternalNames.h"
23c560ce46SValentin Clement (バレンタイン クレメン) #include "flang/Optimizer/Support/Utils.h"
24e1a12767SValentin Clement #include "flang/Semantics/symbol.h"
25e1a12767SValentin Clement #include "flang/Semantics/tools.h"
264d4d4785SKazu Hirata #include <optional>
27e1a12767SValentin Clement 
28af09219eSDaniel Chen static mlir::FunctionType
29af09219eSDaniel Chen getProcedureType(const Fortran::evaluate::characteristics::Procedure &proc,
30af09219eSDaniel Chen                  Fortran::lower::AbstractConverter &converter);
31af09219eSDaniel Chen 
32cedfd272SJean Perier mlir::Type Fortran::lower::getUntypedBoxProcType(mlir::MLIRContext *context) {
33cedfd272SJean Perier   llvm::SmallVector<mlir::Type> resultTys;
34cedfd272SJean Perier   llvm::SmallVector<mlir::Type> inputTys;
35cedfd272SJean Perier   auto untypedFunc = mlir::FunctionType::get(context, inputTys, resultTys);
36cedfd272SJean Perier   return fir::BoxProcType::get(context, untypedFunc);
37cedfd272SJean Perier }
38cedfd272SJean Perier 
39764f95a8SValentin Clement /// Return the type of a dummy procedure given its characteristic (if it has
40764f95a8SValentin Clement /// one).
41cedfd272SJean Perier static mlir::Type getProcedureDesignatorType(
42764f95a8SValentin Clement     const Fortran::evaluate::characteristics::Procedure *,
43764f95a8SValentin Clement     Fortran::lower::AbstractConverter &converter) {
44764f95a8SValentin Clement   // TODO: Get actual function type of the dummy procedure, at least when an
45764f95a8SValentin Clement   // interface is given. The result type should be available even if the arity
46764f95a8SValentin Clement   // and type of the arguments is not.
47764f95a8SValentin Clement   // In general, that is a nice to have but we cannot guarantee to find the
48764f95a8SValentin Clement   // function type that will match the one of the calls, we may not even know
49764f95a8SValentin Clement   // how many arguments the dummy procedure accepts (e.g. if a procedure
50764f95a8SValentin Clement   // pointer is only transiting through the current procedure without being
51764f95a8SValentin Clement   // called), so a function type cast must always be inserted.
52cedfd272SJean Perier   return Fortran::lower::getUntypedBoxProcType(&converter.getMLIRContext());
53764f95a8SValentin Clement }
54764f95a8SValentin Clement 
55e1a12767SValentin Clement //===----------------------------------------------------------------------===//
56d0b70a07SValentin Clement // Caller side interface implementation
57d0b70a07SValentin Clement //===----------------------------------------------------------------------===//
58d0b70a07SValentin Clement 
59d0b70a07SValentin Clement bool Fortran::lower::CallerInterface::hasAlternateReturns() const {
60d0b70a07SValentin Clement   return procRef.hasAlternateReturns();
61d0b70a07SValentin Clement }
62d0b70a07SValentin Clement 
6388684317SjeanPerier /// Return the binding label (from BIND(C...)) or the mangled name of the
6488684317SjeanPerier /// symbol.
6588684317SjeanPerier static std::string
6688684317SjeanPerier getProcMangledName(const Fortran::evaluate::ProcedureDesignator &proc,
6788684317SjeanPerier                    Fortran::lower::AbstractConverter &converter) {
68d0b70a07SValentin Clement   if (const Fortran::semantics::Symbol *symbol = proc.GetSymbol())
69b797a6aeSjeanPerier     return converter.mangleName(symbol->GetUltimate());
70d0b70a07SValentin Clement   assert(proc.GetSpecificIntrinsic() &&
71d0b70a07SValentin Clement          "expected intrinsic procedure in designator");
72d0b70a07SValentin Clement   return proc.GetName();
73d0b70a07SValentin Clement }
74d0b70a07SValentin Clement 
7588684317SjeanPerier std::string Fortran::lower::CallerInterface::getMangledName() const {
7688684317SjeanPerier   return getProcMangledName(procRef.proc(), converter);
7788684317SjeanPerier }
7888684317SjeanPerier 
79d0b70a07SValentin Clement const Fortran::semantics::Symbol *
80d0b70a07SValentin Clement Fortran::lower::CallerInterface::getProcedureSymbol() const {
81d0b70a07SValentin Clement   return procRef.proc().GetSymbol();
82d0b70a07SValentin Clement }
83d0b70a07SValentin Clement 
84d0b70a07SValentin Clement bool Fortran::lower::CallerInterface::isIndirectCall() const {
85d0b70a07SValentin Clement   if (const Fortran::semantics::Symbol *symbol = procRef.proc().GetSymbol())
86d0b70a07SValentin Clement     return Fortran::semantics::IsPointer(*symbol) ||
87d0b70a07SValentin Clement            Fortran::semantics::IsDummy(*symbol);
88d0b70a07SValentin Clement   return false;
89d0b70a07SValentin Clement }
90d0b70a07SValentin Clement 
917883900cSValentin Clement bool Fortran::lower::CallerInterface::requireDispatchCall() const {
92c373f581SjeanPerier   // Procedure pointer component reference do not require dispatch, but
93c373f581SjeanPerier   // have PASS/NOPASS argument.
94c373f581SjeanPerier   if (const Fortran::semantics::Symbol *sym = procRef.proc().GetSymbol())
95c373f581SjeanPerier     if (Fortran::semantics::IsPointer(*sym))
96c373f581SjeanPerier       return false;
977883900cSValentin Clement   // calls with NOPASS attribute still have their component so check if it is
987883900cSValentin Clement   // polymorphic.
997883900cSValentin Clement   if (const Fortran::evaluate::Component *component =
1007883900cSValentin Clement           procRef.proc().GetComponent()) {
10167f9b5aeSValentin Clement (バレンタイン クレメン)     if (Fortran::semantics::IsPolymorphic(component->base().GetLastSymbol()))
1027883900cSValentin Clement       return true;
1037883900cSValentin Clement   }
1047883900cSValentin Clement   // calls with PASS attribute have the passed-object already set in its
1057883900cSValentin Clement   // arguments. Just check if their is one.
1067883900cSValentin Clement   std::optional<unsigned> passArg = getPassArgIndex();
1077883900cSValentin Clement   if (passArg)
1087883900cSValentin Clement     return true;
1097883900cSValentin Clement   return false;
1107883900cSValentin Clement }
1117883900cSValentin Clement 
1127883900cSValentin Clement std::optional<unsigned>
1137883900cSValentin Clement Fortran::lower::CallerInterface::getPassArgIndex() const {
1147883900cSValentin Clement   unsigned passArgIdx = 0;
11591682b26SKazu Hirata   std::optional<unsigned> passArg;
1167883900cSValentin Clement   for (const auto &arg : getCallDescription().arguments()) {
1177883900cSValentin Clement     if (arg && arg->isPassedObject()) {
1187883900cSValentin Clement       passArg = passArgIdx;
1197883900cSValentin Clement       break;
1207883900cSValentin Clement     }
1217883900cSValentin Clement     ++passArgIdx;
1227883900cSValentin Clement   }
123e6319cdcSValentin Clement   if (!passArg)
124e6319cdcSValentin Clement     return passArg;
125e6319cdcSValentin Clement   // Take into account result inserted as arguments.
126e6319cdcSValentin Clement   if (std::optional<Fortran::lower::CallInterface<
127e6319cdcSValentin Clement           Fortran::lower::CallerInterface>::PassedEntity>
128e6319cdcSValentin Clement           resultArg = getPassedResult()) {
129e6319cdcSValentin Clement     if (resultArg->passBy == PassEntityBy::AddressAndLength)
130e6319cdcSValentin Clement       passArg = *passArg + 2;
131e6319cdcSValentin Clement     else if (resultArg->passBy == PassEntityBy::BaseAddress)
132e6319cdcSValentin Clement       passArg = *passArg + 1;
133e6319cdcSValentin Clement   }
1347883900cSValentin Clement   return passArg;
1357883900cSValentin Clement }
1367883900cSValentin Clement 
137c373f581SjeanPerier mlir::Value Fortran::lower::CallerInterface::getIfPassedArg() const {
138c373f581SjeanPerier   if (std::optional<unsigned> passArg = getPassArgIndex()) {
139c373f581SjeanPerier     assert(actualInputs.size() > *passArg && actualInputs[*passArg] &&
140c373f581SjeanPerier            "passed arg was not set yet");
141c373f581SjeanPerier     return actualInputs[*passArg];
142c373f581SjeanPerier   }
143c373f581SjeanPerier   return {};
144c373f581SjeanPerier }
145c373f581SjeanPerier 
146c373f581SjeanPerier const Fortran::evaluate::ProcedureDesignator *
147c373f581SjeanPerier Fortran::lower::CallerInterface::getIfIndirectCall() const {
148d0b70a07SValentin Clement   if (const Fortran::semantics::Symbol *symbol = procRef.proc().GetSymbol())
149d0b70a07SValentin Clement     if (Fortran::semantics::IsPointer(*symbol) ||
150d0b70a07SValentin Clement         Fortran::semantics::IsDummy(*symbol))
151c373f581SjeanPerier       return &procRef.proc();
152d0b70a07SValentin Clement   return nullptr;
153d0b70a07SValentin Clement }
154d0b70a07SValentin Clement 
15588684317SjeanPerier static mlir::Location
15688684317SjeanPerier getProcedureDesignatorLoc(const Fortran::evaluate::ProcedureDesignator &proc,
15788684317SjeanPerier                           Fortran::lower::AbstractConverter &converter) {
15888684317SjeanPerier   // Note: If the callee is defined in the same file but after the current
159d0b70a07SValentin Clement   // unit we cannot get its location here and the funcOp is created at the
160d0b70a07SValentin Clement   // wrong location (i.e, the caller location).
16188684317SjeanPerier   // To prevent this, it is up to the bridge to first declare all functions
16288684317SjeanPerier   // defined in the translation unit before lowering any calls or procedure
16388684317SjeanPerier   // designator references.
164d0b70a07SValentin Clement   if (const Fortran::semantics::Symbol *symbol = proc.GetSymbol())
165d0b70a07SValentin Clement     return converter.genLocation(symbol->name());
166d0b70a07SValentin Clement   // Use current location for intrinsics.
167d0b70a07SValentin Clement   return converter.getCurrentLocation();
168d0b70a07SValentin Clement }
169d0b70a07SValentin Clement 
17088684317SjeanPerier mlir::Location Fortran::lower::CallerInterface::getCalleeLocation() const {
17188684317SjeanPerier   return getProcedureDesignatorLoc(procRef.proc(), converter);
17288684317SjeanPerier }
17388684317SjeanPerier 
174d0b70a07SValentin Clement // Get dummy argument characteristic for a procedure with implicit interface
175d0b70a07SValentin Clement // from the actual argument characteristic. The actual argument may not be a F77
176d0b70a07SValentin Clement // entity. The attribute must be dropped and the shape, if any, must be made
177d0b70a07SValentin Clement // explicit.
178d0b70a07SValentin Clement static Fortran::evaluate::characteristics::DummyDataObject
179d0b70a07SValentin Clement asImplicitArg(Fortran::evaluate::characteristics::DummyDataObject &&dummy) {
18073cf0142SjeanPerier   std::optional<Fortran::evaluate::Shape> shape =
18173cf0142SjeanPerier       dummy.type.attrs().none()
18273cf0142SjeanPerier           ? dummy.type.shape()
18373cf0142SjeanPerier           : std::make_optional<Fortran::evaluate::Shape>(dummy.type.Rank());
184d0b70a07SValentin Clement   return Fortran::evaluate::characteristics::DummyDataObject(
185d0b70a07SValentin Clement       Fortran::evaluate::characteristics::TypeAndShape(dummy.type.type(),
186d0b70a07SValentin Clement                                                        std::move(shape)));
187d0b70a07SValentin Clement }
188d0b70a07SValentin Clement 
189d0b70a07SValentin Clement static Fortran::evaluate::characteristics::DummyArgument
190d0b70a07SValentin Clement asImplicitArg(Fortran::evaluate::characteristics::DummyArgument &&dummy) {
19177d8cfb3SAlexander Shaposhnikov   return Fortran::common::visit(
192d0b70a07SValentin Clement       Fortran::common::visitors{
193d0b70a07SValentin Clement           [&](Fortran::evaluate::characteristics::DummyDataObject &obj) {
194d0b70a07SValentin Clement             return Fortran::evaluate::characteristics::DummyArgument(
195d0b70a07SValentin Clement                 std::move(dummy.name), asImplicitArg(std::move(obj)));
196d0b70a07SValentin Clement           },
197d0b70a07SValentin Clement           [&](Fortran::evaluate::characteristics::DummyProcedure &proc) {
198d0b70a07SValentin Clement             return Fortran::evaluate::characteristics::DummyArgument(
199d0b70a07SValentin Clement                 std::move(dummy.name), std::move(proc));
200d0b70a07SValentin Clement           },
201d0b70a07SValentin Clement           [](Fortran::evaluate::characteristics::AlternateReturn &x) {
202d0b70a07SValentin Clement             return Fortran::evaluate::characteristics::DummyArgument(
203d0b70a07SValentin Clement                 std::move(x));
204d0b70a07SValentin Clement           }},
205d0b70a07SValentin Clement       dummy.u);
206d0b70a07SValentin Clement }
207d0b70a07SValentin Clement 
20892e904b9SJean Perier static bool isExternalDefinedInSameCompilationUnit(
20992e904b9SJean Perier     const Fortran::evaluate::ProcedureDesignator &proc) {
21092e904b9SJean Perier   if (const auto *symbol{proc.GetSymbol()})
21192e904b9SJean Perier     return symbol->has<Fortran::semantics::SubprogramDetails>() &&
21292e904b9SJean Perier            symbol->owner().IsGlobal();
21392e904b9SJean Perier   return false;
21492e904b9SJean Perier }
21592e904b9SJean Perier 
216d0b70a07SValentin Clement Fortran::evaluate::characteristics::Procedure
217d0b70a07SValentin Clement Fortran::lower::CallerInterface::characterize() const {
218d0b70a07SValentin Clement   Fortran::evaluate::FoldingContext &foldingContext =
219d0b70a07SValentin Clement       converter.getFoldingContext();
220d0b70a07SValentin Clement   std::optional<Fortran::evaluate::characteristics::Procedure> characteristic =
221d0b70a07SValentin Clement       Fortran::evaluate::characteristics::Procedure::Characterize(
222cb263919SPeter Klausler           procRef.proc(), foldingContext, /*emitError=*/false);
223d0b70a07SValentin Clement   assert(characteristic && "Failed to get characteristic from procRef");
224d0b70a07SValentin Clement   // The characteristic may not contain the argument characteristic if the
22592e904b9SJean Perier   // ProcedureDesignator has no interface, or may mismatch in case of implicit
22692e904b9SJean Perier   // interface.
22792e904b9SJean Perier   if (!characteristic->HasExplicitInterface() ||
22892e904b9SJean Perier       (converter.getLoweringOptions().getLowerToHighLevelFIR() &&
22992e904b9SJean Perier        isExternalDefinedInSameCompilationUnit(procRef.proc()) &&
23092e904b9SJean Perier        characteristic->CanBeCalledViaImplicitInterface())) {
23192e904b9SJean Perier     // In HLFIR lowering, calls to subprogram with implicit interfaces are
23292e904b9SJean Perier     // always prepared according to the actual arguments. This is to support
23392e904b9SJean Perier     // cases where the implicit interfaces are "abused" in old and not so old
23492e904b9SJean Perier     // Fortran code (e.g, passing REAL(8) to CHARACTER(8), passing object
23592e904b9SJean Perier     // pointers to procedure dummies, passing regular procedure dummies to
23692e904b9SJean Perier     // character procedure dummies, omitted arguments....).
23792e904b9SJean Perier     // In all those case, if the subprogram definition is in the same
23892e904b9SJean Perier     // compilation unit, the "characteristic" from Characterize will be the one
23992e904b9SJean Perier     // from the definition, in case of "abuses" (for which semantics raise a
24092e904b9SJean Perier     // warning), lowering will be placed in a difficult position if it is given
24192e904b9SJean Perier     // the dummy characteristic from the definition and an actual that has
24292e904b9SJean Perier     // seemingly nothing to do with it: it would need to battle to anticipate
24392e904b9SJean Perier     // and handle these mismatches (e.g., be able to prepare a fir.boxchar<>
24492e904b9SJean Perier     // from a fir.real<> and so one). This was the approach of the lowering to
24592e904b9SJean Perier     // FIR, and usually lead to compiler bug every time a new "abuse" was met in
24692e904b9SJean Perier     // the wild.
24792e904b9SJean Perier     // Instead, in HLFIR, the dummy characteristic is always computed from the
24892e904b9SJean Perier     // actual for subprogram with implicit interfaces, and in case of call site
24992e904b9SJean Perier     // vs fun.func MLIR function type signature mismatch, a function cast is
25092e904b9SJean Perier     // done before placing the call. This is a hammer that should cover all
25192e904b9SJean Perier     // cases and behave like existing compiler that "do not see" the definition
25292e904b9SJean Perier     // when placing the call.
25392e904b9SJean Perier     characteristic->dummyArguments.clear();
254d0b70a07SValentin Clement     for (const std::optional<Fortran::evaluate::ActualArgument> &arg :
255d0b70a07SValentin Clement          procRef.arguments()) {
25692e904b9SJean Perier       // "arg" may be null if this is a call with missing arguments compared
25792e904b9SJean Perier       // to the subprogram definition. Do not compute any characteristic
25892e904b9SJean Perier       // in this case.
25992e904b9SJean Perier       if (arg.has_value()) {
260d0b70a07SValentin Clement         if (arg.value().isAlternateReturn()) {
261d0b70a07SValentin Clement           characteristic->dummyArguments.emplace_back(
262d0b70a07SValentin Clement               Fortran::evaluate::characteristics::AlternateReturn{});
263d0b70a07SValentin Clement         } else {
264d0b70a07SValentin Clement           // Argument cannot be optional with implicit interface
265d0b70a07SValentin Clement           const Fortran::lower::SomeExpr *expr = arg.value().UnwrapExpr();
26692e904b9SJean Perier           assert(expr && "argument in call with implicit interface cannot be "
26792e904b9SJean Perier                          "assumed type");
268d0b70a07SValentin Clement           std::optional<Fortran::evaluate::characteristics::DummyArgument>
269d0b70a07SValentin Clement               argCharacteristic =
270d0b70a07SValentin Clement                   Fortran::evaluate::characteristics::DummyArgument::FromActual(
27129fd3e2aSPeter Klausler                       "actual", *expr, foldingContext,
27229fd3e2aSPeter Klausler                       /*forImplicitInterface=*/true);
273d0b70a07SValentin Clement           assert(argCharacteristic &&
274d0b70a07SValentin Clement                  "failed to characterize argument in implicit call");
275d0b70a07SValentin Clement           characteristic->dummyArguments.emplace_back(
276d0b70a07SValentin Clement               asImplicitArg(std::move(*argCharacteristic)));
277d0b70a07SValentin Clement         }
278d0b70a07SValentin Clement       }
279d0b70a07SValentin Clement     }
28092e904b9SJean Perier   }
281d0b70a07SValentin Clement   return *characteristic;
282d0b70a07SValentin Clement }
283d0b70a07SValentin Clement 
284d0b70a07SValentin Clement void Fortran::lower::CallerInterface::placeInput(
285d0b70a07SValentin Clement     const PassedEntity &passedEntity, mlir::Value arg) {
286d0b70a07SValentin Clement   assert(static_cast<int>(actualInputs.size()) > passedEntity.firArgument &&
287d0b70a07SValentin Clement          passedEntity.firArgument >= 0 &&
288d0b70a07SValentin Clement          passedEntity.passBy != CallInterface::PassEntityBy::AddressAndLength &&
289d0b70a07SValentin Clement          "bad arg position");
290d0b70a07SValentin Clement   actualInputs[passedEntity.firArgument] = arg;
291d0b70a07SValentin Clement }
292d0b70a07SValentin Clement 
293d0b70a07SValentin Clement void Fortran::lower::CallerInterface::placeAddressAndLengthInput(
294d0b70a07SValentin Clement     const PassedEntity &passedEntity, mlir::Value addr, mlir::Value len) {
295d0b70a07SValentin Clement   assert(static_cast<int>(actualInputs.size()) > passedEntity.firArgument &&
296d0b70a07SValentin Clement          static_cast<int>(actualInputs.size()) > passedEntity.firLength &&
297d0b70a07SValentin Clement          passedEntity.firArgument >= 0 && passedEntity.firLength >= 0 &&
298d0b70a07SValentin Clement          passedEntity.passBy == CallInterface::PassEntityBy::AddressAndLength &&
299d0b70a07SValentin Clement          "bad arg position");
300d0b70a07SValentin Clement   actualInputs[passedEntity.firArgument] = addr;
301d0b70a07SValentin Clement   actualInputs[passedEntity.firLength] = len;
302d0b70a07SValentin Clement }
303d0b70a07SValentin Clement 
304d0b70a07SValentin Clement bool Fortran::lower::CallerInterface::verifyActualInputs() const {
305d0b70a07SValentin Clement   if (getNumFIRArguments() != actualInputs.size())
306d0b70a07SValentin Clement     return false;
307d0b70a07SValentin Clement   for (mlir::Value arg : actualInputs) {
308d0b70a07SValentin Clement     if (!arg)
309d0b70a07SValentin Clement       return false;
310d0b70a07SValentin Clement   }
311d0b70a07SValentin Clement   return true;
312d0b70a07SValentin Clement }
313d0b70a07SValentin Clement 
3148eee2360SjeanPerier mlir::Value
3158eee2360SjeanPerier Fortran::lower::CallerInterface::getInput(const PassedEntity &passedEntity) {
3168eee2360SjeanPerier   return actualInputs[passedEntity.firArgument];
3178eee2360SjeanPerier }
3188eee2360SjeanPerier 
3198eee2360SjeanPerier static void walkLengths(
3208eee2360SjeanPerier     const Fortran::evaluate::characteristics::TypeAndShape &typeAndShape,
3218eee2360SjeanPerier     const Fortran::lower::CallerInterface::ExprVisitor &visitor,
3228eee2360SjeanPerier     Fortran::lower::AbstractConverter &converter) {
3238eee2360SjeanPerier   Fortran::evaluate::DynamicType dynamicType = typeAndShape.type();
3248eee2360SjeanPerier   // Visit length specification expressions that are explicit.
325d0b70a07SValentin Clement   if (dynamicType.category() == Fortran::common::TypeCategory::Character) {
326d0b70a07SValentin Clement     if (std::optional<Fortran::evaluate::ExtentExpr> length =
327d0b70a07SValentin Clement             dynamicType.GetCharLength())
3288eee2360SjeanPerier       visitor(toEvExpr(*length), /*assumedSize=*/false);
3298eee2360SjeanPerier   } else if (dynamicType.category() == Fortran::common::TypeCategory::Derived &&
3308d692b4bSValentin Clement              !dynamicType.IsUnlimitedPolymorphic()) {
331589d51eaSValentin Clement     const Fortran::semantics::DerivedTypeSpec &derivedTypeSpec =
332589d51eaSValentin Clement         dynamicType.GetDerivedTypeSpec();
333589d51eaSValentin Clement     if (Fortran::semantics::CountLenParameters(derivedTypeSpec) > 0)
334589d51eaSValentin Clement       TODO(converter.getCurrentLocation(),
335589d51eaSValentin Clement            "function result with derived type length parameters");
336d0b70a07SValentin Clement   }
337d0b70a07SValentin Clement }
338d0b70a07SValentin Clement 
3398eee2360SjeanPerier void Fortran::lower::CallerInterface::walkResultLengths(
3408eee2360SjeanPerier     const ExprVisitor &visitor) const {
3418eee2360SjeanPerier   assert(characteristic && "characteristic was not computed");
3428eee2360SjeanPerier   const Fortran::evaluate::characteristics::FunctionResult &result =
3438eee2360SjeanPerier       characteristic->functionResult.value();
3448eee2360SjeanPerier   const Fortran::evaluate::characteristics::TypeAndShape *typeAndShape =
3458eee2360SjeanPerier       result.GetTypeAndShape();
3468eee2360SjeanPerier   assert(typeAndShape && "no result type");
3478eee2360SjeanPerier   return walkLengths(*typeAndShape, visitor, converter);
3488eee2360SjeanPerier }
3498eee2360SjeanPerier 
3508eee2360SjeanPerier void Fortran::lower::CallerInterface::walkDummyArgumentLengths(
3518eee2360SjeanPerier     const PassedEntity &passedEntity, const ExprVisitor &visitor) const {
3528eee2360SjeanPerier   if (!passedEntity.characteristics)
3538eee2360SjeanPerier     return;
3548eee2360SjeanPerier   if (const auto *dummy =
3558eee2360SjeanPerier           std::get_if<Fortran::evaluate::characteristics::DummyDataObject>(
3568eee2360SjeanPerier               &passedEntity.characteristics->u))
3578eee2360SjeanPerier     walkLengths(dummy->type, visitor, converter);
3588eee2360SjeanPerier }
3598eee2360SjeanPerier 
360d0b70a07SValentin Clement // Compute extent expr from shapeSpec of an explicit shape.
361d0b70a07SValentin Clement static Fortran::evaluate::ExtentExpr
362d0b70a07SValentin Clement getExtentExpr(const Fortran::semantics::ShapeSpec &shapeSpec) {
3638eee2360SjeanPerier   if (shapeSpec.ubound().isStar())
3648eee2360SjeanPerier     // F'2023 18.5.3 point 5.
3658eee2360SjeanPerier     return Fortran::evaluate::ExtentExpr{-1};
366d0b70a07SValentin Clement   const auto &ubound = shapeSpec.ubound().GetExplicit();
367d0b70a07SValentin Clement   const auto &lbound = shapeSpec.lbound().GetExplicit();
368d0b70a07SValentin Clement   assert(lbound && ubound && "shape must be explicit");
369d0b70a07SValentin Clement   return Fortran::common::Clone(*ubound) - Fortran::common::Clone(*lbound) +
370d0b70a07SValentin Clement          Fortran::evaluate::ExtentExpr{1};
371d0b70a07SValentin Clement }
372d0b70a07SValentin Clement 
3738eee2360SjeanPerier static void
3748eee2360SjeanPerier walkExtents(const Fortran::semantics::Symbol &symbol,
3758eee2360SjeanPerier             const Fortran::lower::CallerInterface::ExprVisitor &visitor) {
3768eee2360SjeanPerier   if (const auto *objectDetails =
3778eee2360SjeanPerier           symbol.detailsIf<Fortran::semantics::ObjectEntityDetails>())
3788eee2360SjeanPerier     if (objectDetails->shape().IsExplicitShape() ||
3798eee2360SjeanPerier         Fortran::semantics::IsAssumedSizeArray(symbol))
3808eee2360SjeanPerier       for (const Fortran::semantics::ShapeSpec &shapeSpec :
3818eee2360SjeanPerier            objectDetails->shape())
3828eee2360SjeanPerier         visitor(Fortran::evaluate::AsGenericExpr(getExtentExpr(shapeSpec)),
3838eee2360SjeanPerier                 /*assumedSize=*/shapeSpec.ubound().isStar());
3848eee2360SjeanPerier }
3858eee2360SjeanPerier 
386d0b70a07SValentin Clement void Fortran::lower::CallerInterface::walkResultExtents(
3878eee2360SjeanPerier     const ExprVisitor &visitor) const {
388d0b70a07SValentin Clement   // Walk directly the result symbol shape (the characteristic shape may contain
389d0b70a07SValentin Clement   // descriptor inquiries to it that would fail to lower on the caller side).
390fe252f8eSValentin Clement   const Fortran::semantics::SubprogramDetails *interfaceDetails =
391fe252f8eSValentin Clement       getInterfaceDetails();
392fe252f8eSValentin Clement   if (interfaceDetails) {
3938eee2360SjeanPerier     walkExtents(interfaceDetails->result(), visitor);
394d0b70a07SValentin Clement   } else {
395d0b70a07SValentin Clement     if (procRef.Rank() != 0)
396d0b70a07SValentin Clement       fir::emitFatalError(
397d0b70a07SValentin Clement           converter.getCurrentLocation(),
398d0b70a07SValentin Clement           "only scalar functions may not have an interface symbol");
399d0b70a07SValentin Clement   }
400d0b70a07SValentin Clement }
401d0b70a07SValentin Clement 
4028eee2360SjeanPerier void Fortran::lower::CallerInterface::walkDummyArgumentExtents(
4038eee2360SjeanPerier     const PassedEntity &passedEntity, const ExprVisitor &visitor) const {
4048eee2360SjeanPerier   const Fortran::semantics::SubprogramDetails *interfaceDetails =
4058eee2360SjeanPerier       getInterfaceDetails();
4068eee2360SjeanPerier   if (!interfaceDetails)
4078eee2360SjeanPerier     return;
4088eee2360SjeanPerier   const Fortran::semantics::Symbol *dummy = getDummySymbol(passedEntity);
4098eee2360SjeanPerier   assert(dummy && "dummy symbol was not set");
4108eee2360SjeanPerier   walkExtents(*dummy, visitor);
4118eee2360SjeanPerier }
4128eee2360SjeanPerier 
4138eee2360SjeanPerier bool Fortran::lower::CallerInterface::mustMapInterfaceSymbolsForResult() const {
414d0b70a07SValentin Clement   assert(characteristic && "characteristic was not computed");
415d0b70a07SValentin Clement   const std::optional<Fortran::evaluate::characteristics::FunctionResult>
416d0b70a07SValentin Clement       &result = characteristic->functionResult;
417d0b70a07SValentin Clement   if (!result || result->CanBeReturnedViaImplicitInterface() ||
418cdb320b4SDaniel Chen       !getInterfaceDetails() || result->IsProcedurePointer())
419d0b70a07SValentin Clement     return false;
420d0b70a07SValentin Clement   bool allResultSpecExprConstant = true;
4218eee2360SjeanPerier   auto visitor = [&](const Fortran::lower::SomeExpr &e, bool) {
422d0b70a07SValentin Clement     allResultSpecExprConstant &= Fortran::evaluate::IsConstantExpr(e);
423d0b70a07SValentin Clement   };
424d0b70a07SValentin Clement   walkResultLengths(visitor);
425d0b70a07SValentin Clement   walkResultExtents(visitor);
426d0b70a07SValentin Clement   return !allResultSpecExprConstant;
427d0b70a07SValentin Clement }
428d0b70a07SValentin Clement 
4298eee2360SjeanPerier bool Fortran::lower::CallerInterface::mustMapInterfaceSymbolsForDummyArgument(
4308eee2360SjeanPerier     const PassedEntity &arg) const {
4318eee2360SjeanPerier   bool allResultSpecExprConstant = true;
4328eee2360SjeanPerier   auto visitor = [&](const Fortran::lower::SomeExpr &e, bool) {
4338eee2360SjeanPerier     allResultSpecExprConstant &= Fortran::evaluate::IsConstantExpr(e);
4348eee2360SjeanPerier   };
4358eee2360SjeanPerier   walkDummyArgumentLengths(arg, visitor);
4368eee2360SjeanPerier   walkDummyArgumentExtents(arg, visitor);
4378eee2360SjeanPerier   return !allResultSpecExprConstant;
4388eee2360SjeanPerier }
4398eee2360SjeanPerier 
440d0b70a07SValentin Clement mlir::Value Fortran::lower::CallerInterface::getArgumentValue(
441d0b70a07SValentin Clement     const semantics::Symbol &sym) const {
442d0b70a07SValentin Clement   mlir::Location loc = converter.getCurrentLocation();
443fe252f8eSValentin Clement   const Fortran::semantics::SubprogramDetails *ifaceDetails =
444fe252f8eSValentin Clement       getInterfaceDetails();
445fe252f8eSValentin Clement   if (!ifaceDetails)
446d0b70a07SValentin Clement     fir::emitFatalError(
447d0b70a07SValentin Clement         loc, "mapping actual and dummy arguments requires an interface");
448d0b70a07SValentin Clement   const std::vector<Fortran::semantics::Symbol *> &dummies =
449fe252f8eSValentin Clement       ifaceDetails->dummyArgs();
450d0b70a07SValentin Clement   auto it = std::find(dummies.begin(), dummies.end(), &sym);
451d0b70a07SValentin Clement   if (it == dummies.end())
452d0b70a07SValentin Clement     fir::emitFatalError(loc, "symbol is not a dummy in this call");
453d0b70a07SValentin Clement   FirValue mlirArgIndex = passedArguments[it - dummies.begin()].firArgument;
454d0b70a07SValentin Clement   return actualInputs[mlirArgIndex];
455d0b70a07SValentin Clement }
456d0b70a07SValentin Clement 
4578eee2360SjeanPerier const Fortran::semantics::Symbol *
4588eee2360SjeanPerier Fortran::lower::CallerInterface::getDummySymbol(
4598eee2360SjeanPerier     const PassedEntity &passedEntity) const {
4608eee2360SjeanPerier   const Fortran::semantics::SubprogramDetails *ifaceDetails =
4618eee2360SjeanPerier       getInterfaceDetails();
4628eee2360SjeanPerier   if (!ifaceDetails)
4638eee2360SjeanPerier     return nullptr;
4648eee2360SjeanPerier   std::size_t argPosition = 0;
4658eee2360SjeanPerier   for (const auto &arg : getPassedArguments()) {
4668eee2360SjeanPerier     if (&arg == &passedEntity)
4678eee2360SjeanPerier       break;
4688eee2360SjeanPerier     ++argPosition;
4698eee2360SjeanPerier   }
4708eee2360SjeanPerier   if (argPosition >= ifaceDetails->dummyArgs().size())
4718eee2360SjeanPerier     return nullptr;
4728eee2360SjeanPerier   return ifaceDetails->dummyArgs()[argPosition];
4738eee2360SjeanPerier }
4748eee2360SjeanPerier 
475d0b70a07SValentin Clement mlir::Type Fortran::lower::CallerInterface::getResultStorageType() const {
476d0b70a07SValentin Clement   if (passedResult)
477d0b70a07SValentin Clement     return fir::dyn_cast_ptrEleTy(inputs[passedResult->firArgument].type);
478d0b70a07SValentin Clement   assert(saveResult && !outputs.empty());
479d0b70a07SValentin Clement   return outputs[0].type;
480d0b70a07SValentin Clement }
481d0b70a07SValentin Clement 
4828eee2360SjeanPerier mlir::Type Fortran::lower::CallerInterface::getDummyArgumentType(
4838eee2360SjeanPerier     const PassedEntity &passedEntity) const {
4848eee2360SjeanPerier   return inputs[passedEntity.firArgument].type;
4858eee2360SjeanPerier }
4868eee2360SjeanPerier 
487d0b70a07SValentin Clement const Fortran::semantics::Symbol &
488d0b70a07SValentin Clement Fortran::lower::CallerInterface::getResultSymbol() const {
489d0b70a07SValentin Clement   mlir::Location loc = converter.getCurrentLocation();
490fe252f8eSValentin Clement   const Fortran::semantics::SubprogramDetails *ifaceDetails =
491fe252f8eSValentin Clement       getInterfaceDetails();
492fe252f8eSValentin Clement   if (!ifaceDetails)
493d0b70a07SValentin Clement     fir::emitFatalError(
494d0b70a07SValentin Clement         loc, "mapping actual and dummy arguments requires an interface");
495fe252f8eSValentin Clement   return ifaceDetails->result();
496fe252f8eSValentin Clement }
497fe252f8eSValentin Clement 
498fe252f8eSValentin Clement const Fortran::semantics::SubprogramDetails *
499fe252f8eSValentin Clement Fortran::lower::CallerInterface::getInterfaceDetails() const {
500fe252f8eSValentin Clement   if (const Fortran::semantics::Symbol *iface =
501fe252f8eSValentin Clement           procRef.proc().GetInterfaceSymbol())
502fe252f8eSValentin Clement     return iface->GetUltimate()
503fe252f8eSValentin Clement         .detailsIf<Fortran::semantics::SubprogramDetails>();
504fe252f8eSValentin Clement   return nullptr;
505d0b70a07SValentin Clement }
506d0b70a07SValentin Clement 
507d0b70a07SValentin Clement //===----------------------------------------------------------------------===//
508e1a12767SValentin Clement // Callee side interface implementation
509e1a12767SValentin Clement //===----------------------------------------------------------------------===//
510e1a12767SValentin Clement 
511ad40cc14SValentin Clement bool Fortran::lower::CalleeInterface::hasAlternateReturns() const {
512ad40cc14SValentin Clement   return !funit.isMainProgram() &&
513ad40cc14SValentin Clement          Fortran::semantics::HasAlternateReturns(funit.getSubprogramSymbol());
514ad40cc14SValentin Clement }
515ad40cc14SValentin Clement 
516e1a12767SValentin Clement std::string Fortran::lower::CalleeInterface::getMangledName() const {
517e1a12767SValentin Clement   if (funit.isMainProgram())
518e1a12767SValentin Clement     return fir::NameUniquer::doProgramEntry().str();
519b797a6aeSjeanPerier   return converter.mangleName(funit.getSubprogramSymbol());
520e1a12767SValentin Clement }
521e1a12767SValentin Clement 
522e1a12767SValentin Clement const Fortran::semantics::Symbol *
523e1a12767SValentin Clement Fortran::lower::CalleeInterface::getProcedureSymbol() const {
524e1a12767SValentin Clement   if (funit.isMainProgram())
5252c538401SRenaud-K     return funit.getMainProgramSymbol();
526e1a12767SValentin Clement   return &funit.getSubprogramSymbol();
527e1a12767SValentin Clement }
528e1a12767SValentin Clement 
529e1a12767SValentin Clement mlir::Location Fortran::lower::CalleeInterface::getCalleeLocation() const {
530e1a12767SValentin Clement   // FIXME: do NOT use unknown for the anonymous PROGRAM case. We probably
531e1a12767SValentin Clement   // should just stash the location in the funit regardless.
532e1a12767SValentin Clement   return converter.genLocation(funit.getStartingSourceLoc());
533e1a12767SValentin Clement }
534e1a12767SValentin Clement 
535ad40cc14SValentin Clement Fortran::evaluate::characteristics::Procedure
536ad40cc14SValentin Clement Fortran::lower::CalleeInterface::characterize() const {
537ad40cc14SValentin Clement   Fortran::evaluate::FoldingContext &foldingContext =
538ad40cc14SValentin Clement       converter.getFoldingContext();
539ad40cc14SValentin Clement   std::optional<Fortran::evaluate::characteristics::Procedure> characteristic =
540ad40cc14SValentin Clement       Fortran::evaluate::characteristics::Procedure::Characterize(
541ad40cc14SValentin Clement           funit.getSubprogramSymbol(), foldingContext);
542ad40cc14SValentin Clement   assert(characteristic && "Fail to get characteristic from symbol");
543ad40cc14SValentin Clement   return *characteristic;
544ad40cc14SValentin Clement }
545ad40cc14SValentin Clement 
546ad40cc14SValentin Clement bool Fortran::lower::CalleeInterface::isMainProgram() const {
547ad40cc14SValentin Clement   return funit.isMainProgram();
548ad40cc14SValentin Clement }
549ad40cc14SValentin Clement 
55058ceae95SRiver Riddle mlir::func::FuncOp
55158ceae95SRiver Riddle Fortran::lower::CalleeInterface::addEntryBlockAndMapArguments() {
55210b23ae8SValentin Clement   // Check for bugs in the front end. The front end must not present multiple
55310b23ae8SValentin Clement   // definitions of the same procedure.
55410b23ae8SValentin Clement   if (!func.getBlocks().empty())
55510b23ae8SValentin Clement     fir::emitFatalError(func.getLoc(),
55610b23ae8SValentin Clement                         "cannot process subprogram that was already processed");
55710b23ae8SValentin Clement 
55810b23ae8SValentin Clement   // On the callee side, directly map the mlir::value argument of the function
55910b23ae8SValentin Clement   // block to the Fortran symbols.
560e1a12767SValentin Clement   func.addEntryBlock();
561da7c77b8SValentin Clement   mapPassedEntities();
562e1a12767SValentin Clement   return func;
563e1a12767SValentin Clement }
564e1a12767SValentin Clement 
565764f95a8SValentin Clement bool Fortran::lower::CalleeInterface::hasHostAssociated() const {
56693129ca8SJean Perier   return funit.parentHasTupleHostAssoc();
567764f95a8SValentin Clement }
568764f95a8SValentin Clement 
569764f95a8SValentin Clement mlir::Type Fortran::lower::CalleeInterface::getHostAssociatedTy() const {
570764f95a8SValentin Clement   assert(hasHostAssociated());
571764f95a8SValentin Clement   return funit.parentHostAssoc().getArgumentType(converter);
572764f95a8SValentin Clement }
573764f95a8SValentin Clement 
574764f95a8SValentin Clement mlir::Value Fortran::lower::CalleeInterface::getHostAssociatedTuple() const {
575764f95a8SValentin Clement   assert(hasHostAssociated() || !funit.getHostAssoc().empty());
576764f95a8SValentin Clement   return converter.hostAssocTupleValue();
577764f95a8SValentin Clement }
578764f95a8SValentin Clement 
579e1a12767SValentin Clement //===----------------------------------------------------------------------===//
5802c143345SV Donaldson // CallInterface implementation: this part is common to both caller and callee.
581e1a12767SValentin Clement //===----------------------------------------------------------------------===//
582e1a12767SValentin Clement 
58358ceae95SRiver Riddle static void addSymbolAttribute(mlir::func::FuncOp func,
584e1a12767SValentin Clement                                const Fortran::semantics::Symbol &sym,
585d9250061SjeanPerier                                fir::FortranProcedureFlagsEnumAttr procAttrs,
586e1a12767SValentin Clement                                mlir::MLIRContext &mlirContext) {
587971237daSjeanPerier   const Fortran::semantics::Symbol &ultimate = sym.GetUltimate();
588971237daSjeanPerier   // The link between an internal procedure and its host procedure is lost
589971237daSjeanPerier   // in FIR if the host is BIND(C) since the internal mangling will not
590971237daSjeanPerier   // allow retrieving the host bind(C) name, and therefore func.func symbol.
591971237daSjeanPerier   // Preserve it as an attribute so that this can be later retrieved.
592971237daSjeanPerier   if (Fortran::semantics::ClassifyProcedure(ultimate) ==
593971237daSjeanPerier       Fortran::semantics::ProcedureDefinitionClass::Internal) {
594971237daSjeanPerier     if (ultimate.owner().kind() ==
595971237daSjeanPerier         Fortran::semantics::Scope::Kind::Subprogram) {
596971237daSjeanPerier       if (const Fortran::semantics::Symbol *hostProcedure =
597971237daSjeanPerier               ultimate.owner().symbol()) {
598971237daSjeanPerier         std::string hostName = Fortran::lower::mangle::mangleName(
599971237daSjeanPerier             *hostProcedure, /*keepExternalInScope=*/true);
600971237daSjeanPerier         func->setAttr(
601971237daSjeanPerier             fir::getHostSymbolAttrName(),
602971237daSjeanPerier             mlir::SymbolRefAttr::get(
603971237daSjeanPerier                 &mlirContext, mlir::StringAttr::get(&mlirContext, hostName)));
604971237daSjeanPerier       }
605971237daSjeanPerier     } else if (ultimate.owner().kind() ==
606971237daSjeanPerier                Fortran::semantics::Scope::Kind::MainProgram) {
607971237daSjeanPerier       func->setAttr(fir::getHostSymbolAttrName(),
608971237daSjeanPerier                     mlir::SymbolRefAttr::get(
609971237daSjeanPerier                         &mlirContext,
610971237daSjeanPerier                         mlir::StringAttr::get(
611971237daSjeanPerier                             &mlirContext, fir::NameUniquer::doProgramEntry())));
612971237daSjeanPerier     }
613971237daSjeanPerier   }
614971237daSjeanPerier 
615d9250061SjeanPerier   if (procAttrs)
616d9250061SjeanPerier     func->setAttr(fir::getFortranProcedureFlagsAttrName(), procAttrs);
6171551c094SValentin Clement (バレンタイン クレメン) 
618e1a12767SValentin Clement   // Only add this on bind(C) functions for which the symbol is not reflected in
619e1a12767SValentin Clement   // the current context.
620e1a12767SValentin Clement   if (!Fortran::semantics::IsBindCProcedure(sym))
621e1a12767SValentin Clement     return;
622e1a12767SValentin Clement   std::string name =
623e1a12767SValentin Clement       Fortran::lower::mangle::mangleName(sym, /*keepExternalInScope=*/true);
624e1a12767SValentin Clement   func->setAttr(fir::getSymbolAttrName(),
625e1a12767SValentin Clement                 mlir::StringAttr::get(&mlirContext, name));
626e1a12767SValentin Clement }
627e1a12767SValentin Clement 
628d79c3c50SValentin Clement (バレンタイン クレメン) static void
629d79c3c50SValentin Clement (バレンタイン クレメン) setCUDAAttributes(mlir::func::FuncOp func,
630d79c3c50SValentin Clement (バレンタイン クレメン)                   const Fortran::semantics::Symbol *sym,
631d79c3c50SValentin Clement (バレンタイン クレメン)                   std::optional<Fortran::evaluate::characteristics::Procedure>
632d79c3c50SValentin Clement (バレンタイン クレメン)                       characteristic) {
633d79c3c50SValentin Clement (バレンタイン クレメン)   if (characteristic && characteristic->cudaSubprogramAttrs) {
634d79c3c50SValentin Clement (バレンタイン クレメン)     func.getOperation()->setAttr(
63545daa4fdSValentin Clement (バレンタイン クレメン)         cuf::getProcAttrName(),
63645daa4fdSValentin Clement (バレンタイン クレメン)         cuf::getProcAttribute(func.getContext(),
637d79c3c50SValentin Clement (バレンタイン クレメン)                               *characteristic->cudaSubprogramAttrs));
638d79c3c50SValentin Clement (バレンタイン クレメン)   }
639d79c3c50SValentin Clement (バレンタイン クレメン) 
640d79c3c50SValentin Clement (バレンタイン クレメン)   if (sym) {
641d79c3c50SValentin Clement (バレンタイン クレメン)     if (auto details =
642d79c3c50SValentin Clement (バレンタイン クレメン)             sym->GetUltimate()
643d79c3c50SValentin Clement (バレンタイン クレメン)                 .detailsIf<Fortran::semantics::SubprogramDetails>()) {
6445e3c7e3aSValentin Clement (バレンタイン クレメン)       mlir::Type i64Ty = mlir::IntegerType::get(func.getContext(), 64);
645d79c3c50SValentin Clement (バレンタイン クレメン)       if (!details->cudaLaunchBounds().empty()) {
646d79c3c50SValentin Clement (バレンタイン クレメン)         assert(details->cudaLaunchBounds().size() >= 2 &&
647d79c3c50SValentin Clement (バレンタイン クレメン)                "expect at least 2 values");
648d79c3c50SValentin Clement (バレンタイン クレメン)         auto maxTPBAttr =
649d79c3c50SValentin Clement (バレンタイン クレメン)             mlir::IntegerAttr::get(i64Ty, details->cudaLaunchBounds()[0]);
650d79c3c50SValentin Clement (バレンタイン クレメン)         auto minBPMAttr =
651d79c3c50SValentin Clement (バレンタイン クレメン)             mlir::IntegerAttr::get(i64Ty, details->cudaLaunchBounds()[1]);
652d79c3c50SValentin Clement (バレンタイン クレメン)         mlir::IntegerAttr ubAttr;
653d79c3c50SValentin Clement (バレンタイン クレメン)         if (details->cudaLaunchBounds().size() > 2)
654d79c3c50SValentin Clement (バレンタイン クレメン)           ubAttr =
655d79c3c50SValentin Clement (バレンタイン クレメン)               mlir::IntegerAttr::get(i64Ty, details->cudaLaunchBounds()[2]);
656d79c3c50SValentin Clement (バレンタイン クレメン)         func.getOperation()->setAttr(
65745daa4fdSValentin Clement (バレンタイン クレメン)             cuf::getLaunchBoundsAttrName(),
65845daa4fdSValentin Clement (バレンタイン クレメン)             cuf::LaunchBoundsAttr::get(func.getContext(), maxTPBAttr,
659d79c3c50SValentin Clement (バレンタイン クレメン)                                        minBPMAttr, ubAttr));
660d79c3c50SValentin Clement (バレンタイン クレメン)       }
6615e3c7e3aSValentin Clement (バレンタイン クレメン) 
6625e3c7e3aSValentin Clement (バレンタイン クレメン)       if (!details->cudaClusterDims().empty()) {
6635e3c7e3aSValentin Clement (バレンタイン クレメン)         assert(details->cudaClusterDims().size() == 3 && "expect 3 values");
6645e3c7e3aSValentin Clement (バレンタイン クレメン)         auto xAttr =
6655e3c7e3aSValentin Clement (バレンタイン クレメン)             mlir::IntegerAttr::get(i64Ty, details->cudaClusterDims()[0]);
6665e3c7e3aSValentin Clement (バレンタイン クレメン)         auto yAttr =
6675e3c7e3aSValentin Clement (バレンタイン クレメン)             mlir::IntegerAttr::get(i64Ty, details->cudaClusterDims()[1]);
6685e3c7e3aSValentin Clement (バレンタイン クレメン)         auto zAttr =
6695e3c7e3aSValentin Clement (バレンタイン クレメン)             mlir::IntegerAttr::get(i64Ty, details->cudaClusterDims()[2]);
6705e3c7e3aSValentin Clement (バレンタイン クレメン)         func.getOperation()->setAttr(
67145daa4fdSValentin Clement (バレンタイン クレメン)             cuf::getClusterDimsAttrName(),
67245daa4fdSValentin Clement (バレンタイン クレメン)             cuf::ClusterDimsAttr::get(func.getContext(), xAttr, yAttr, zAttr));
6735e3c7e3aSValentin Clement (バレンタイン クレメン)       }
674d79c3c50SValentin Clement (バレンタイン クレメン)     }
675d79c3c50SValentin Clement (バレンタイン クレメン)   }
676d79c3c50SValentin Clement (バレンタイン クレメン) }
677d79c3c50SValentin Clement (バレンタイン クレメン) 
678e1a12767SValentin Clement /// Declare drives the different actions to be performed while analyzing the
67958ceae95SRiver Riddle /// signature and building/finding the mlir::func::FuncOp.
680e1a12767SValentin Clement template <typename T>
681e1a12767SValentin Clement void Fortran::lower::CallInterface<T>::declare() {
682ad40cc14SValentin Clement   if (!side().isMainProgram()) {
683ad40cc14SValentin Clement     characteristic.emplace(side().characterize());
684ad40cc14SValentin Clement     bool isImplicit = characteristic->CanBeCalledViaImplicitInterface();
685ad40cc14SValentin Clement     determineInterface(isImplicit, *characteristic);
686ad40cc14SValentin Clement   }
687ad40cc14SValentin Clement   // No input/output for main program
688ad40cc14SValentin Clement 
689e1a12767SValentin Clement   // Create / get funcOp for direct calls. For indirect calls (only meaningful
690e1a12767SValentin Clement   // on the caller side), no funcOp has to be created here. The mlir::Value
691e1a12767SValentin Clement   // holding the indirection is used when creating the fir::CallOp.
692e1a12767SValentin Clement   if (!side().isIndirectCall()) {
693e1a12767SValentin Clement     std::string name = side().getMangledName();
694e1a12767SValentin Clement     mlir::ModuleOp module = converter.getModuleOp();
695a4798bb0SjeanPerier     mlir::SymbolTable *symbolTable = converter.getMLIRSymbolTable();
696a4798bb0SjeanPerier     func = fir::FirOpBuilder::getNamedFunction(module, symbolTable, name);
697e1a12767SValentin Clement     if (!func) {
698e1a12767SValentin Clement       mlir::Location loc = side().getCalleeLocation();
699d9250061SjeanPerier       mlir::MLIRContext &mlirContext = converter.getMLIRContext();
700e1a12767SValentin Clement       mlir::FunctionType ty = genFunctionType();
701a4798bb0SjeanPerier       func =
702a4798bb0SjeanPerier           fir::FirOpBuilder::createFunction(loc, module, name, ty, symbolTable);
7032c538401SRenaud-K       if (const Fortran::semantics::Symbol *sym = side().getProcedureSymbol()) {
7042c538401SRenaud-K         if (side().isMainProgram()) {
7052c538401SRenaud-K           func->setAttr(fir::getSymbolAttrName(),
7062c538401SRenaud-K                         mlir::StringAttr::get(&converter.getMLIRContext(),
7072c538401SRenaud-K                                               sym->name().ToString()));
7082c538401SRenaud-K         } else {
709d9250061SjeanPerier           addSymbolAttribute(func, *sym, getProcedureAttrs(&mlirContext),
710d9250061SjeanPerier                              mlirContext);
7112c538401SRenaud-K         }
7122c538401SRenaud-K       }
713da7c77b8SValentin Clement       for (const auto &placeHolder : llvm::enumerate(inputs))
714da7c77b8SValentin Clement         if (!placeHolder.value().attributes.empty())
715da7c77b8SValentin Clement           func.setArgAttrs(placeHolder.index(), placeHolder.value().attributes);
716d79c3c50SValentin Clement (バレンタイン クレメン) 
717d79c3c50SValentin Clement (バレンタイン クレメン)       setCUDAAttributes(func, side().getProcedureSymbol(), characteristic);
71878145a6bSValentin Clement (バレンタイン クレメン)     }
719e1a12767SValentin Clement   }
720e1a12767SValentin Clement }
721e1a12767SValentin Clement 
72258ceae95SRiver Riddle /// Once the signature has been analyzed and the mlir::func::FuncOp was
72358ceae95SRiver Riddle /// built/found, map the fir inputs to Fortran entities (the symbols or
72458ceae95SRiver Riddle /// expressions).
725da7c77b8SValentin Clement template <typename T>
726da7c77b8SValentin Clement void Fortran::lower::CallInterface<T>::mapPassedEntities() {
727da7c77b8SValentin Clement   // map back fir inputs to passed entities
728da7c77b8SValentin Clement   if constexpr (std::is_same_v<T, Fortran::lower::CalleeInterface>) {
729da7c77b8SValentin Clement     assert(inputs.size() == func.front().getArguments().size() &&
730da7c77b8SValentin Clement            "function previously created with different number of arguments");
731da7c77b8SValentin Clement     for (auto [fst, snd] : llvm::zip(inputs, func.front().getArguments()))
732da7c77b8SValentin Clement       mapBackInputToPassedEntity(fst, snd);
733da7c77b8SValentin Clement   } else {
734da7c77b8SValentin Clement     // On the caller side, map the index of the mlir argument position
735da7c77b8SValentin Clement     // to Fortran ActualArguments.
736da7c77b8SValentin Clement     int firPosition = 0;
737da7c77b8SValentin Clement     for (const FirPlaceHolder &placeHolder : inputs)
738da7c77b8SValentin Clement       mapBackInputToPassedEntity(placeHolder, firPosition++);
739da7c77b8SValentin Clement   }
740da7c77b8SValentin Clement }
741da7c77b8SValentin Clement 
742da7c77b8SValentin Clement template <typename T>
743da7c77b8SValentin Clement void Fortran::lower::CallInterface<T>::mapBackInputToPassedEntity(
744da7c77b8SValentin Clement     const FirPlaceHolder &placeHolder, FirValue firValue) {
745da7c77b8SValentin Clement   PassedEntity &passedEntity =
746da7c77b8SValentin Clement       placeHolder.passedEntityPosition == FirPlaceHolder::resultEntityPosition
747da7c77b8SValentin Clement           ? passedResult.value()
748da7c77b8SValentin Clement           : passedArguments[placeHolder.passedEntityPosition];
749da7c77b8SValentin Clement   if (placeHolder.property == Property::CharLength)
750da7c77b8SValentin Clement     passedEntity.firLength = firValue;
751da7c77b8SValentin Clement   else
752da7c77b8SValentin Clement     passedEntity.firArgument = firValue;
753da7c77b8SValentin Clement }
754da7c77b8SValentin Clement 
755d0b70a07SValentin Clement /// Helpers to access ActualArgument/Symbols
756d0b70a07SValentin Clement static const Fortran::evaluate::ActualArguments &
757d0b70a07SValentin Clement getEntityContainer(const Fortran::evaluate::ProcedureRef &proc) {
758d0b70a07SValentin Clement   return proc.arguments();
759d0b70a07SValentin Clement }
760d0b70a07SValentin Clement 
761da7c77b8SValentin Clement static const std::vector<Fortran::semantics::Symbol *> &
762da7c77b8SValentin Clement getEntityContainer(Fortran::lower::pft::FunctionLikeUnit &funit) {
763da7c77b8SValentin Clement   return funit.getSubprogramSymbol()
764da7c77b8SValentin Clement       .get<Fortran::semantics::SubprogramDetails>()
765da7c77b8SValentin Clement       .dummyArgs();
766da7c77b8SValentin Clement }
767da7c77b8SValentin Clement 
768d0b70a07SValentin Clement static const Fortran::evaluate::ActualArgument *getDataObjectEntity(
769d0b70a07SValentin Clement     const std::optional<Fortran::evaluate::ActualArgument> &arg) {
770d0b70a07SValentin Clement   if (arg)
771d0b70a07SValentin Clement     return &*arg;
772d0b70a07SValentin Clement   return nullptr;
773d0b70a07SValentin Clement }
774d0b70a07SValentin Clement 
775da7c77b8SValentin Clement static const Fortran::semantics::Symbol &
776da7c77b8SValentin Clement getDataObjectEntity(const Fortran::semantics::Symbol *arg) {
777da7c77b8SValentin Clement   assert(arg && "expect symbol for data object entity");
778da7c77b8SValentin Clement   return *arg;
779da7c77b8SValentin Clement }
780da7c77b8SValentin Clement 
78137e84d9bSValentin Clement static const Fortran::evaluate::ActualArgument *
78237e84d9bSValentin Clement getResultEntity(const Fortran::evaluate::ProcedureRef &) {
78337e84d9bSValentin Clement   return nullptr;
78437e84d9bSValentin Clement }
78537e84d9bSValentin Clement 
78637e84d9bSValentin Clement static const Fortran::semantics::Symbol &
78737e84d9bSValentin Clement getResultEntity(Fortran::lower::pft::FunctionLikeUnit &funit) {
78837e84d9bSValentin Clement   return funit.getSubprogramSymbol()
78937e84d9bSValentin Clement       .get<Fortran::semantics::SubprogramDetails>()
79037e84d9bSValentin Clement       .result();
79137e84d9bSValentin Clement }
79237e84d9bSValentin Clement 
793764f95a8SValentin Clement /// Bypass helpers to manipulate entities since they are not any symbol/actual
794764f95a8SValentin Clement /// argument to associate. See SignatureBuilder below.
795764f95a8SValentin Clement using FakeEntity = bool;
796764f95a8SValentin Clement using FakeEntities = llvm::SmallVector<FakeEntity>;
797764f95a8SValentin Clement static FakeEntities
798764f95a8SValentin Clement getEntityContainer(const Fortran::evaluate::characteristics::Procedure &proc) {
799764f95a8SValentin Clement   FakeEntities enities(proc.dummyArguments.size());
800764f95a8SValentin Clement   return enities;
801764f95a8SValentin Clement }
802764f95a8SValentin Clement static const FakeEntity &getDataObjectEntity(const FakeEntity &e) { return e; }
803764f95a8SValentin Clement static FakeEntity
804764f95a8SValentin Clement getResultEntity(const Fortran::evaluate::characteristics::Procedure &proc) {
805764f95a8SValentin Clement   return false;
806764f95a8SValentin Clement }
807ad40cc14SValentin Clement 
808ad40cc14SValentin Clement /// This is the actual part that defines the FIR interface based on the
809ad40cc14SValentin Clement /// characteristic. It directly mutates the CallInterface members.
810ad40cc14SValentin Clement template <typename T>
811ad40cc14SValentin Clement class Fortran::lower::CallInterfaceImpl {
812ad40cc14SValentin Clement   using CallInterface = Fortran::lower::CallInterface<T>;
813da7c77b8SValentin Clement   using PassEntityBy = typename CallInterface::PassEntityBy;
814da7c77b8SValentin Clement   using PassedEntity = typename CallInterface::PassedEntity;
81537e84d9bSValentin Clement   using FirValue = typename CallInterface::FirValue;
816da7c77b8SValentin Clement   using FortranEntity = typename CallInterface::FortranEntity;
817ad40cc14SValentin Clement   using FirPlaceHolder = typename CallInterface::FirPlaceHolder;
818ad40cc14SValentin Clement   using Property = typename CallInterface::Property;
819ad40cc14SValentin Clement   using TypeAndShape = Fortran::evaluate::characteristics::TypeAndShape;
820da7c77b8SValentin Clement   using DummyCharacteristics =
821da7c77b8SValentin Clement       Fortran::evaluate::characteristics::DummyArgument;
822ad40cc14SValentin Clement 
823ad40cc14SValentin Clement public:
824ad40cc14SValentin Clement   CallInterfaceImpl(CallInterface &i)
825ad40cc14SValentin Clement       : interface(i), mlirContext{i.converter.getMLIRContext()} {}
826ad40cc14SValentin Clement 
827ad40cc14SValentin Clement   void buildImplicitInterface(
828ad40cc14SValentin Clement       const Fortran::evaluate::characteristics::Procedure &procedure) {
829ad40cc14SValentin Clement     // Handle result
830ad40cc14SValentin Clement     if (const std::optional<Fortran::evaluate::characteristics::FunctionResult>
831ad40cc14SValentin Clement             &result = procedure.functionResult)
832de3efd1bSValentin Clement       handleImplicitResult(*result, procedure.IsBindC());
833ad40cc14SValentin Clement     else if (interface.side().hasAlternateReturns())
834ad40cc14SValentin Clement       addFirResult(mlir::IndexType::get(&mlirContext),
835ad40cc14SValentin Clement                    FirPlaceHolder::resultEntityPosition, Property::Value);
836da7c77b8SValentin Clement     // Handle arguments
837da7c77b8SValentin Clement     const auto &argumentEntities =
838da7c77b8SValentin Clement         getEntityContainer(interface.side().getCallDescription());
839da7c77b8SValentin Clement     for (auto pair : llvm::zip(procedure.dummyArguments, argumentEntities)) {
840da7c77b8SValentin Clement       const Fortran::evaluate::characteristics::DummyArgument
841da7c77b8SValentin Clement           &argCharacteristics = std::get<0>(pair);
84277d8cfb3SAlexander Shaposhnikov       Fortran::common::visit(
843da7c77b8SValentin Clement           Fortran::common::visitors{
844da7c77b8SValentin Clement               [&](const auto &dummy) {
845da7c77b8SValentin Clement                 const auto &entity = getDataObjectEntity(std::get<1>(pair));
846da7c77b8SValentin Clement                 handleImplicitDummy(&argCharacteristics, dummy, entity);
847da7c77b8SValentin Clement               },
848da7c77b8SValentin Clement               [&](const Fortran::evaluate::characteristics::AlternateReturn &) {
849da7c77b8SValentin Clement                 // nothing to do
850da7c77b8SValentin Clement               },
851da7c77b8SValentin Clement           },
852da7c77b8SValentin Clement           argCharacteristics.u);
853da7c77b8SValentin Clement     }
854ad40cc14SValentin Clement   }
855ad40cc14SValentin Clement 
856c807aa53SValentin Clement   void buildExplicitInterface(
857c807aa53SValentin Clement       const Fortran::evaluate::characteristics::Procedure &procedure) {
858de3efd1bSValentin Clement     bool isBindC = procedure.IsBindC();
859c807aa53SValentin Clement     // Handle result
860c807aa53SValentin Clement     if (const std::optional<Fortran::evaluate::characteristics::FunctionResult>
861c807aa53SValentin Clement             &result = procedure.functionResult) {
862c807aa53SValentin Clement       if (result->CanBeReturnedViaImplicitInterface())
863de3efd1bSValentin Clement         handleImplicitResult(*result, isBindC);
864c807aa53SValentin Clement       else
865c807aa53SValentin Clement         handleExplicitResult(*result);
866c807aa53SValentin Clement     } else if (interface.side().hasAlternateReturns()) {
867c807aa53SValentin Clement       addFirResult(mlir::IndexType::get(&mlirContext),
868c807aa53SValentin Clement                    FirPlaceHolder::resultEntityPosition, Property::Value);
869c807aa53SValentin Clement     }
870914061bbSValentin Clement     // Handle arguments
871914061bbSValentin Clement     const auto &argumentEntities =
872914061bbSValentin Clement         getEntityContainer(interface.side().getCallDescription());
873914061bbSValentin Clement     for (auto pair : llvm::zip(procedure.dummyArguments, argumentEntities)) {
874914061bbSValentin Clement       const Fortran::evaluate::characteristics::DummyArgument
875914061bbSValentin Clement           &argCharacteristics = std::get<0>(pair);
87677d8cfb3SAlexander Shaposhnikov       Fortran::common::visit(
877914061bbSValentin Clement           Fortran::common::visitors{
878914061bbSValentin Clement               [&](const Fortran::evaluate::characteristics::DummyDataObject
879914061bbSValentin Clement                       &dummy) {
880914061bbSValentin Clement                 const auto &entity = getDataObjectEntity(std::get<1>(pair));
8815b6f3fcbSjeanPerier                 if (!isBindC && dummy.CanBePassedViaImplicitInterface())
882914061bbSValentin Clement                   handleImplicitDummy(&argCharacteristics, dummy, entity);
883914061bbSValentin Clement                 else
884914061bbSValentin Clement                   handleExplicitDummy(&argCharacteristics, dummy, entity,
885914061bbSValentin Clement                                       isBindC);
886914061bbSValentin Clement               },
887914061bbSValentin Clement               [&](const Fortran::evaluate::characteristics::DummyProcedure
888914061bbSValentin Clement                       &dummy) {
889914061bbSValentin Clement                 const auto &entity = getDataObjectEntity(std::get<1>(pair));
890914061bbSValentin Clement                 handleImplicitDummy(&argCharacteristics, dummy, entity);
891914061bbSValentin Clement               },
892914061bbSValentin Clement               [&](const Fortran::evaluate::characteristics::AlternateReturn &) {
893914061bbSValentin Clement                 // nothing to do
894914061bbSValentin Clement               },
895914061bbSValentin Clement           },
896914061bbSValentin Clement           argCharacteristics.u);
897914061bbSValentin Clement     }
898c807aa53SValentin Clement   }
899c807aa53SValentin Clement 
900764f95a8SValentin Clement   void appendHostAssocTupleArg(mlir::Type tupTy) {
901092601d4SAndrzej Warzynski     mlir::MLIRContext *ctxt = tupTy.getContext();
902764f95a8SValentin Clement     addFirOperand(tupTy, nextPassedArgPosition(), Property::BaseAddress,
903764f95a8SValentin Clement                   {mlir::NamedAttribute{
904764f95a8SValentin Clement                       mlir::StringAttr::get(ctxt, fir::getHostAssocAttrName()),
905764f95a8SValentin Clement                       mlir::UnitAttr::get(ctxt)}});
906764f95a8SValentin Clement     interface.passedArguments.emplace_back(
907764f95a8SValentin Clement         PassedEntity{PassEntityBy::BaseAddress, std::nullopt,
908764f95a8SValentin Clement                      interface.side().getHostAssociatedTuple(), emptyValue()});
909764f95a8SValentin Clement   }
910764f95a8SValentin Clement 
911c0921586SKazu Hirata   static std::optional<Fortran::evaluate::DynamicType> getResultDynamicType(
912764f95a8SValentin Clement       const Fortran::evaluate::characteristics::Procedure &procedure) {
913764f95a8SValentin Clement     if (const std::optional<Fortran::evaluate::characteristics::FunctionResult>
914764f95a8SValentin Clement             &result = procedure.functionResult)
915764f95a8SValentin Clement       if (const auto *resultTypeAndShape = result->GetTypeAndShape())
916764f95a8SValentin Clement         return resultTypeAndShape->type();
9179a417395SKazu Hirata     return std::nullopt;
918764f95a8SValentin Clement   }
919764f95a8SValentin Clement 
920764f95a8SValentin Clement   static bool mustPassLengthWithDummyProcedure(
921764f95a8SValentin Clement       const Fortran::evaluate::characteristics::Procedure &procedure) {
922764f95a8SValentin Clement     // When passing a character function designator `bar` as dummy procedure to
923764f95a8SValentin Clement     // `foo` (e.g. `foo(bar)`), pass the result length of `bar` to `foo` so that
924764f95a8SValentin Clement     // `bar` can be called inside `foo` even if its length is assumed there.
925764f95a8SValentin Clement     // From an ABI perspective, the extra length argument must be handled
926764f95a8SValentin Clement     // exactly as if passing a character object. Using an argument of
927764f95a8SValentin Clement     // fir.boxchar type gives the expected behavior: after codegen, the
928764f95a8SValentin Clement     // fir.boxchar lengths are added after all the arguments as extra value
929764f95a8SValentin Clement     // arguments (the extra arguments order is the order of the fir.boxchar).
930764f95a8SValentin Clement 
931764f95a8SValentin Clement     // This ABI is compatible with ifort, nag, nvfortran, and xlf, but not
932764f95a8SValentin Clement     // gfortran. Gfortran does not pass the length and is therefore unable to
933764f95a8SValentin Clement     // handle later call to `bar` in `foo` where the length would be assumed. If
934764f95a8SValentin Clement     // the result is an array, nag and ifort and xlf still pass the length, but
935764f95a8SValentin Clement     // not nvfortran (and gfortran). It is not clear it is possible to call an
936764f95a8SValentin Clement     // array function with assumed length (f18 forbides defining such
937764f95a8SValentin Clement     // interfaces). Hence, passing the length is most likely useless, but stick
938764f95a8SValentin Clement     // with ifort/nag/xlf interface here.
939c0921586SKazu Hirata     if (std::optional<Fortran::evaluate::DynamicType> type =
940764f95a8SValentin Clement             getResultDynamicType(procedure))
941764f95a8SValentin Clement       return type->category() == Fortran::common::TypeCategory::Character;
942764f95a8SValentin Clement     return false;
943764f95a8SValentin Clement   }
944764f95a8SValentin Clement 
945ad40cc14SValentin Clement private:
946ad40cc14SValentin Clement   void handleImplicitResult(
947de3efd1bSValentin Clement       const Fortran::evaluate::characteristics::FunctionResult &result,
948de3efd1bSValentin Clement       bool isBindC) {
949bd8bec27SDaniel Chen     if (auto proc{result.IsProcedurePointer()}) {
950bd8bec27SDaniel Chen       mlir::Type mlirType = fir::BoxProcType::get(
951bd8bec27SDaniel Chen           &mlirContext, getProcedureType(*proc, interface.converter));
952bd8bec27SDaniel Chen       addFirResult(mlirType, FirPlaceHolder::resultEntityPosition,
953bd8bec27SDaniel Chen                    Property::Value);
954bd8bec27SDaniel Chen       return;
955bd8bec27SDaniel Chen     }
956ad40cc14SValentin Clement     const Fortran::evaluate::characteristics::TypeAndShape *typeAndShape =
957ad40cc14SValentin Clement         result.GetTypeAndShape();
958ad40cc14SValentin Clement     assert(typeAndShape && "expect type for non proc pointer result");
959ad40cc14SValentin Clement     Fortran::evaluate::DynamicType dynamicType = typeAndShape->type();
96037e84d9bSValentin Clement     // Character result allocated by caller and passed as hidden arguments
961ad40cc14SValentin Clement     if (dynamicType.category() == Fortran::common::TypeCategory::Character) {
962de3efd1bSValentin Clement       if (isBindC) {
963de3efd1bSValentin Clement         mlir::Type mlirType = translateDynamicType(dynamicType);
964de3efd1bSValentin Clement         addFirResult(mlirType, FirPlaceHolder::resultEntityPosition,
965de3efd1bSValentin Clement                      Property::Value);
966de3efd1bSValentin Clement       } else {
96737e84d9bSValentin Clement         handleImplicitCharacterResult(dynamicType);
968de3efd1bSValentin Clement       }
969ad40cc14SValentin Clement     } else if (dynamicType.category() ==
970ad40cc14SValentin Clement                Fortran::common::TypeCategory::Derived) {
971ef934174SKelvin Li       if (!dynamicType.GetDerivedTypeSpec().IsVectorType()) {
972ef934174SKelvin Li         // Derived result need to be allocated by the caller and the result
973ef934174SKelvin Li         // value must be saved. Derived type in implicit interface cannot have
974ef934174SKelvin Li         // length parameters.
975764f95a8SValentin Clement         setSaveResult();
976ef934174SKelvin Li       }
977764f95a8SValentin Clement       mlir::Type mlirType = translateDynamicType(dynamicType);
978764f95a8SValentin Clement       addFirResult(mlirType, FirPlaceHolder::resultEntityPosition,
979764f95a8SValentin Clement                    Property::Value);
980ad40cc14SValentin Clement     } else {
981ad40cc14SValentin Clement       // All result other than characters/derived are simply returned by value
982ad40cc14SValentin Clement       // in implicit interfaces
983ad40cc14SValentin Clement       mlir::Type mlirType =
984ad40cc14SValentin Clement           getConverter().genType(dynamicType.category(), dynamicType.kind());
985ad40cc14SValentin Clement       addFirResult(mlirType, FirPlaceHolder::resultEntityPosition,
986ad40cc14SValentin Clement                    Property::Value);
987ad40cc14SValentin Clement     }
988ad40cc14SValentin Clement   }
98937e84d9bSValentin Clement   void
99037e84d9bSValentin Clement   handleImplicitCharacterResult(const Fortran::evaluate::DynamicType &type) {
99137e84d9bSValentin Clement     int resultPosition = FirPlaceHolder::resultEntityPosition;
99237e84d9bSValentin Clement     setPassedResult(PassEntityBy::AddressAndLength,
99337e84d9bSValentin Clement                     getResultEntity(interface.side().getCallDescription()));
99437e84d9bSValentin Clement     mlir::Type lenTy = mlir::IndexType::get(&mlirContext);
99537e84d9bSValentin Clement     std::optional<std::int64_t> constantLen = type.knownLength();
99637e84d9bSValentin Clement     fir::CharacterType::LenType len =
99737e84d9bSValentin Clement         constantLen ? *constantLen : fir::CharacterType::unknownLen();
99837e84d9bSValentin Clement     mlir::Type charRefTy = fir::ReferenceType::get(
99937e84d9bSValentin Clement         fir::CharacterType::get(&mlirContext, type.kind(), len));
100037e84d9bSValentin Clement     mlir::Type boxCharTy = fir::BoxCharType::get(&mlirContext, type.kind());
100137e84d9bSValentin Clement     addFirOperand(charRefTy, resultPosition, Property::CharAddress);
100237e84d9bSValentin Clement     addFirOperand(lenTy, resultPosition, Property::CharLength);
100337e84d9bSValentin Clement     /// For now, also return it by boxchar
100437e84d9bSValentin Clement     addFirResult(boxCharTy, resultPosition, Property::BoxChar);
100537e84d9bSValentin Clement   }
100637e84d9bSValentin Clement 
1007da7c77b8SValentin Clement   /// Return a vector with an attribute with the name of the argument if this
1008da7c77b8SValentin Clement   /// is a callee interface and the name is available. Otherwise, just return
1009da7c77b8SValentin Clement   /// an empty vector.
1010da7c77b8SValentin Clement   llvm::SmallVector<mlir::NamedAttribute>
1011da7c77b8SValentin Clement   dummyNameAttr(const FortranEntity &entity) {
1012da7c77b8SValentin Clement     if constexpr (std::is_same_v<FortranEntity,
1013da7c77b8SValentin Clement                                  std::optional<Fortran::common::Reference<
1014da7c77b8SValentin Clement                                      const Fortran::semantics::Symbol>>>) {
1015da7c77b8SValentin Clement       if (entity.has_value()) {
1016da7c77b8SValentin Clement         const Fortran::semantics::Symbol *argument = &*entity.value();
1017da7c77b8SValentin Clement         // "fir.bindc_name" is used for arguments for the sake of consistency
1018da7c77b8SValentin Clement         // with other attributes carrying surface syntax names in FIR.
1019da7c77b8SValentin Clement         return {mlir::NamedAttribute(
1020da7c77b8SValentin Clement             mlir::StringAttr::get(&mlirContext, "fir.bindc_name"),
1021da7c77b8SValentin Clement             mlir::StringAttr::get(&mlirContext,
1022da7c77b8SValentin Clement                                   toStringRef(argument->name())))};
1023ad40cc14SValentin Clement       }
1024da7c77b8SValentin Clement     }
1025da7c77b8SValentin Clement     return {};
1026da7c77b8SValentin Clement   }
1027da7c77b8SValentin Clement 
10280a10e889SjeanPerier   mlir::Type
10290a10e889SjeanPerier   getRefType(Fortran::evaluate::DynamicType dynamicType,
10300a10e889SjeanPerier              const Fortran::evaluate::characteristics::DummyDataObject &obj) {
10310a10e889SjeanPerier     mlir::Type type = translateDynamicType(dynamicType);
1032a49f630cSjeanPerier     if (std::optional<fir::SequenceType::Shape> bounds = getBounds(obj.type))
1033a49f630cSjeanPerier       type = fir::SequenceType::get(*bounds, type);
10340a10e889SjeanPerier     return fir::ReferenceType::get(type);
10350a10e889SjeanPerier   }
10360a10e889SjeanPerier 
1037764f95a8SValentin Clement   void handleImplicitDummy(
1038764f95a8SValentin Clement       const DummyCharacteristics *characteristics,
1039764f95a8SValentin Clement       const Fortran::evaluate::characteristics::DummyDataObject &obj,
1040764f95a8SValentin Clement       const FortranEntity &entity) {
1041764f95a8SValentin Clement     Fortran::evaluate::DynamicType dynamicType = obj.type.type();
10420a10e889SjeanPerier     if constexpr (std::is_same_v<FortranEntity,
10430a10e889SjeanPerier                                  const Fortran::evaluate::ActualArgument *>) {
10440a10e889SjeanPerier       if (entity) {
10450a10e889SjeanPerier         if (entity->isPercentVal()) {
10460a10e889SjeanPerier           mlir::Type type = translateDynamicType(dynamicType);
10470a10e889SjeanPerier           addFirOperand(type, nextPassedArgPosition(), Property::Value,
10480a10e889SjeanPerier                         dummyNameAttr(entity));
10490a10e889SjeanPerier           addPassedArg(PassEntityBy::Value, entity, characteristics);
10500a10e889SjeanPerier           return;
10510a10e889SjeanPerier         }
10520a10e889SjeanPerier         if (entity->isPercentRef()) {
10530a10e889SjeanPerier           mlir::Type refType = getRefType(dynamicType, obj);
10540a10e889SjeanPerier           addFirOperand(refType, nextPassedArgPosition(), Property::BaseAddress,
10550a10e889SjeanPerier                         dummyNameAttr(entity));
10560a10e889SjeanPerier           addPassedArg(PassEntityBy::BaseAddress, entity, characteristics);
10570a10e889SjeanPerier           return;
10580a10e889SjeanPerier         }
10590a10e889SjeanPerier       }
10600a10e889SjeanPerier     }
1061764f95a8SValentin Clement     if (dynamicType.category() == Fortran::common::TypeCategory::Character) {
1062764f95a8SValentin Clement       mlir::Type boxCharTy =
1063764f95a8SValentin Clement           fir::BoxCharType::get(&mlirContext, dynamicType.kind());
1064764f95a8SValentin Clement       addFirOperand(boxCharTy, nextPassedArgPosition(), Property::BoxChar,
1065764f95a8SValentin Clement                     dummyNameAttr(entity));
1066764f95a8SValentin Clement       addPassedArg(PassEntityBy::BoxChar, entity, characteristics);
1067764f95a8SValentin Clement     } else {
1068764f95a8SValentin Clement       // non-PDT derived type allowed in implicit interface.
10690a10e889SjeanPerier       mlir::Type refType = getRefType(dynamicType, obj);
1070764f95a8SValentin Clement       addFirOperand(refType, nextPassedArgPosition(), Property::BaseAddress,
1071764f95a8SValentin Clement                     dummyNameAttr(entity));
1072764f95a8SValentin Clement       addPassedArg(PassEntityBy::BaseAddress, entity, characteristics);
1073764f95a8SValentin Clement     }
1074764f95a8SValentin Clement   }
1075764f95a8SValentin Clement 
1076914061bbSValentin Clement   mlir::Type
1077914061bbSValentin Clement   translateDynamicType(const Fortran::evaluate::DynamicType &dynamicType) {
1078914061bbSValentin Clement     Fortran::common::TypeCategory cat = dynamicType.category();
1079914061bbSValentin Clement     // DERIVED
1080914061bbSValentin Clement     if (cat == Fortran::common::TypeCategory::Derived) {
10819d99b482SValentin Clement       if (dynamicType.IsUnlimitedPolymorphic())
10829d99b482SValentin Clement         return mlir::NoneType::get(&mlirContext);
1083589d51eaSValentin Clement       return getConverter().genType(dynamicType.GetDerivedTypeSpec());
1084914061bbSValentin Clement     }
1085914061bbSValentin Clement     // CHARACTER with compile time constant length.
1086914061bbSValentin Clement     if (cat == Fortran::common::TypeCategory::Character)
108796d9df41SValentin Clement       if (std::optional<std::int64_t> constantLen =
108896d9df41SValentin Clement               toInt64(dynamicType.GetCharLength()))
108996d9df41SValentin Clement         return getConverter().genType(cat, dynamicType.kind(), {*constantLen});
1090914061bbSValentin Clement     // INTEGER, REAL, LOGICAL, COMPLEX, and CHARACTER with dynamic length.
1091914061bbSValentin Clement     return getConverter().genType(cat, dynamicType.kind());
1092914061bbSValentin Clement   }
1093914061bbSValentin Clement 
1094914061bbSValentin Clement   void handleExplicitDummy(
1095914061bbSValentin Clement       const DummyCharacteristics *characteristics,
1096914061bbSValentin Clement       const Fortran::evaluate::characteristics::DummyDataObject &obj,
1097914061bbSValentin Clement       const FortranEntity &entity, bool isBindC) {
1098914061bbSValentin Clement     using Attrs = Fortran::evaluate::characteristics::DummyDataObject::Attr;
1099914061bbSValentin Clement 
1100914061bbSValentin Clement     bool isValueAttr = false;
1101914061bbSValentin Clement     [[maybe_unused]] mlir::Location loc =
1102914061bbSValentin Clement         interface.converter.getCurrentLocation();
1103914061bbSValentin Clement     llvm::SmallVector<mlir::NamedAttribute> attrs = dummyNameAttr(entity);
1104914061bbSValentin Clement     auto addMLIRAttr = [&](llvm::StringRef attr) {
1105914061bbSValentin Clement       attrs.emplace_back(mlir::StringAttr::get(&mlirContext, attr),
1106914061bbSValentin Clement                          mlir::UnitAttr::get(&mlirContext));
1107914061bbSValentin Clement     };
1108914061bbSValentin Clement     if (obj.attrs.test(Attrs::Optional))
1109914061bbSValentin Clement       addMLIRAttr(fir::getOptionalAttrName());
1110914061bbSValentin Clement     if (obj.attrs.test(Attrs::Contiguous))
1111914061bbSValentin Clement       addMLIRAttr(fir::getContiguousAttrName());
1112914061bbSValentin Clement     if (obj.attrs.test(Attrs::Value))
1113914061bbSValentin Clement       isValueAttr = true; // TODO: do we want an mlir::Attribute as well?
11140b54e33fSs-watanabe314     if (obj.attrs.test(Attrs::Volatile)) {
1115331145e6SValentin Clement       TODO(loc, "VOLATILE in procedure interface");
11160b54e33fSs-watanabe314       addMLIRAttr(fir::getVolatileAttrName());
11170b54e33fSs-watanabe314     }
11180b54e33fSs-watanabe314     // obj.attrs.test(Attrs::Asynchronous) does not impact the way the argument
11190b54e33fSs-watanabe314     // is passed given flang implement asynch IO synchronously. However, it's
11200b54e33fSs-watanabe314     // added to determine whether the argument is captured.
11210b54e33fSs-watanabe314     // TODO: it would be safer to treat them as volatile because since Fortran
11220b54e33fSs-watanabe314     // 2018 asynchronous can also be used for C defined asynchronous user
11230b54e33fSs-watanabe314     // processes (see 18.10.4 Asynchronous communication).
11240b54e33fSs-watanabe314     if (obj.attrs.test(Attrs::Asynchronous))
11250b54e33fSs-watanabe314       addMLIRAttr(fir::getAsynchronousAttrName());
1126914061bbSValentin Clement     if (obj.attrs.test(Attrs::Target))
1127914061bbSValentin Clement       addMLIRAttr(fir::getTargetAttrName());
1128c560ce46SValentin Clement (バレンタイン クレメン)     if (obj.cudaDataAttr)
1129c560ce46SValentin Clement (バレンタイン クレメン)       attrs.emplace_back(
113045daa4fdSValentin Clement (バレンタイン クレメン)           mlir::StringAttr::get(&mlirContext, cuf::getDataAttrName()),
113145daa4fdSValentin Clement (バレンタイン クレメン)           cuf::getDataAttribute(&mlirContext, obj.cudaDataAttr));
1132914061bbSValentin Clement 
1133914061bbSValentin Clement     // TODO: intents that require special care (e.g finalization)
1134914061bbSValentin Clement 
1135*d732c86cSPeter Klausler     if (obj.type.corank() > 0)
11365db4779cSPete Steinfeld       TODO(loc, "coarray: dummy argument coarray in procedure interface");
1137914061bbSValentin Clement 
1138914061bbSValentin Clement     // So far assume that if the argument cannot be passed by implicit interface
1139914061bbSValentin Clement     // it must be by box. That may no be always true (e.g for simple optionals)
1140914061bbSValentin Clement 
1141914061bbSValentin Clement     Fortran::evaluate::DynamicType dynamicType = obj.type.type();
1142914061bbSValentin Clement     mlir::Type type = translateDynamicType(dynamicType);
1143a49f630cSjeanPerier     if (std::optional<fir::SequenceType::Shape> bounds = getBounds(obj.type))
1144a49f630cSjeanPerier       type = fir::SequenceType::get(*bounds, type);
1145914061bbSValentin Clement     if (obj.attrs.test(Attrs::Allocatable))
1146914061bbSValentin Clement       type = fir::HeapType::get(type);
1147914061bbSValentin Clement     if (obj.attrs.test(Attrs::Pointer))
1148914061bbSValentin Clement       type = fir::PointerType::get(type);
11493eef2c2bSValentin Clement     mlir::Type boxType = fir::wrapInClassOrBoxType(
11503eef2c2bSValentin Clement         type, obj.type.type().IsPolymorphic(), obj.type.type().IsAssumedType());
1151914061bbSValentin Clement 
115225ce9867SJean Perier     if (obj.attrs.test(Attrs::Allocatable) || obj.attrs.test(Attrs::Pointer)) {
11539d99b482SValentin Clement       // Pass as fir.ref<fir.box> or fir.ref<fir.class>
1154914061bbSValentin Clement       mlir::Type boxRefType = fir::ReferenceType::get(boxType);
1155914061bbSValentin Clement       addFirOperand(boxRefType, nextPassedArgPosition(), Property::MutableBox,
1156914061bbSValentin Clement                     attrs);
1157914061bbSValentin Clement       addPassedArg(PassEntityBy::MutableBox, entity, characteristics);
1158b477d39bSjeanPerier     } else if (obj.IsPassedByDescriptor(isBindC)) {
11599d99b482SValentin Clement       // Pass as fir.box or fir.class
11608803211aSAnthony Cabrera       if (isValueAttr &&
11618803211aSAnthony Cabrera           !getConverter().getLoweringOptions().getLowerToHighLevelFIR())
1162f5b29a7aSValentin Clement         TODO(loc, "assumed shape dummy argument with VALUE attribute");
1163914061bbSValentin Clement       addFirOperand(boxType, nextPassedArgPosition(), Property::Box, attrs);
1164914061bbSValentin Clement       addPassedArg(PassEntityBy::Box, entity, characteristics);
1165914061bbSValentin Clement     } else if (dynamicType.category() ==
1166914061bbSValentin Clement                Fortran::common::TypeCategory::Character) {
1167ad4e1abaSjeanPerier       if (isValueAttr && isBindC) {
1168ad4e1abaSjeanPerier         // Pass as fir.char<1>
1169ad4e1abaSjeanPerier         mlir::Type charTy =
1170ad4e1abaSjeanPerier             fir::CharacterType::getSingleton(&mlirContext, dynamicType.kind());
1171ad4e1abaSjeanPerier         addFirOperand(charTy, nextPassedArgPosition(), Property::Value, attrs);
1172ad4e1abaSjeanPerier         addPassedArg(PassEntityBy::Value, entity, characteristics);
1173ad4e1abaSjeanPerier       } else {
1174914061bbSValentin Clement         // Pass as fir.box_char
1175914061bbSValentin Clement         mlir::Type boxCharTy =
1176914061bbSValentin Clement             fir::BoxCharType::get(&mlirContext, dynamicType.kind());
1177914061bbSValentin Clement         addFirOperand(boxCharTy, nextPassedArgPosition(), Property::BoxChar,
1178914061bbSValentin Clement                       attrs);
1179914061bbSValentin Clement         addPassedArg(isValueAttr ? PassEntityBy::CharBoxValueAttribute
1180914061bbSValentin Clement                                  : PassEntityBy::BoxChar,
1181914061bbSValentin Clement                      entity, characteristics);
1182ad4e1abaSjeanPerier       }
1183914061bbSValentin Clement     } else {
1184d3c0dd6eSPeixin Qiao       // Pass as fir.ref unless it's by VALUE and BIND(C). Also pass-by-value
1185d3c0dd6eSPeixin Qiao       // for numerical/logical scalar without OPTIONAL so that the behavior is
1186d3c0dd6eSPeixin Qiao       // consistent with gfortran/nvfortran.
1187d3c0dd6eSPeixin Qiao       // TODO: pass-by-value for derived type is not supported yet
1188914061bbSValentin Clement       mlir::Type passType = fir::ReferenceType::get(type);
1189914061bbSValentin Clement       PassEntityBy passBy = PassEntityBy::BaseAddress;
1190914061bbSValentin Clement       Property prop = Property::BaseAddress;
1191914061bbSValentin Clement       if (isValueAttr) {
1192fe9409b9SPeixin Qiao         bool isBuiltinCptrType = fir::isa_builtin_cptr_type(type);
1193fac349a1SChristian Sigg         if (isBindC || (!mlir::isa<fir::SequenceType>(type) &&
1194d3c0dd6eSPeixin Qiao                         !obj.attrs.test(Attrs::Optional) &&
1195fe9409b9SPeixin Qiao                         (dynamicType.category() !=
1196fe9409b9SPeixin Qiao                              Fortran::common::TypeCategory::Derived ||
1197fe9409b9SPeixin Qiao                          isBuiltinCptrType))) {
1198914061bbSValentin Clement           passBy = PassEntityBy::Value;
1199914061bbSValentin Clement           prop = Property::Value;
1200fe9409b9SPeixin Qiao           if (isBuiltinCptrType) {
1201fac349a1SChristian Sigg             auto recTy = mlir::dyn_cast<fir::RecordType>(type);
12024943dbdfSPeixin Qiao             mlir::Type fieldTy = recTy.getTypeList()[0].second;
12034943dbdfSPeixin Qiao             passType = fir::ReferenceType::get(fieldTy);
12044943dbdfSPeixin Qiao           } else {
1205914061bbSValentin Clement             passType = type;
12064943dbdfSPeixin Qiao           }
1207914061bbSValentin Clement         } else {
1208914061bbSValentin Clement           passBy = PassEntityBy::BaseAddressValueAttribute;
1209914061bbSValentin Clement         }
1210914061bbSValentin Clement       }
1211914061bbSValentin Clement       addFirOperand(passType, nextPassedArgPosition(), prop, attrs);
1212914061bbSValentin Clement       addPassedArg(passBy, entity, characteristics);
1213914061bbSValentin Clement     }
1214914061bbSValentin Clement   }
1215914061bbSValentin Clement 
1216da7c77b8SValentin Clement   void handleImplicitDummy(
1217da7c77b8SValentin Clement       const DummyCharacteristics *characteristics,
1218da7c77b8SValentin Clement       const Fortran::evaluate::characteristics::DummyProcedure &proc,
1219da7c77b8SValentin Clement       const FortranEntity &entity) {
1220af09219eSDaniel Chen     if (!interface.converter.getLoweringOptions().getLowerToHighLevelFIR() &&
1221af09219eSDaniel Chen         proc.attrs.test(
1222764f95a8SValentin Clement             Fortran::evaluate::characteristics::DummyProcedure::Attr::Pointer))
1223da7c77b8SValentin Clement       TODO(interface.converter.getCurrentLocation(),
1224764f95a8SValentin Clement            "procedure pointer arguments");
1225764f95a8SValentin Clement     const Fortran::evaluate::characteristics::Procedure &procedure =
1226764f95a8SValentin Clement         proc.procedure.value();
1227764f95a8SValentin Clement     mlir::Type funcType =
1228764f95a8SValentin Clement         getProcedureDesignatorType(&procedure, interface.converter);
1229af09219eSDaniel Chen     if (proc.attrs.test(Fortran::evaluate::characteristics::DummyProcedure::
1230af09219eSDaniel Chen                             Attr::Pointer)) {
1231af09219eSDaniel Chen       // Prodecure pointer dummy argument.
1232af09219eSDaniel Chen       funcType = fir::ReferenceType::get(funcType);
1233af09219eSDaniel Chen       addFirOperand(funcType, nextPassedArgPosition(), Property::BoxProcRef);
1234af09219eSDaniel Chen       addPassedArg(PassEntityBy::BoxProcRef, entity, characteristics);
1235af09219eSDaniel Chen       return;
1236af09219eSDaniel Chen     }
1237af09219eSDaniel Chen     // Otherwise, it is a dummy procedure.
1238c0921586SKazu Hirata     std::optional<Fortran::evaluate::DynamicType> resultTy =
1239764f95a8SValentin Clement         getResultDynamicType(procedure);
1240764f95a8SValentin Clement     if (resultTy && mustPassLengthWithDummyProcedure(procedure)) {
1241764f95a8SValentin Clement       // The result length of dummy procedures that are character functions must
1242764f95a8SValentin Clement       // be passed so that the dummy procedure can be called if it has assumed
1243764f95a8SValentin Clement       // length on the callee side.
1244764f95a8SValentin Clement       mlir::Type tupleType =
1245764f95a8SValentin Clement           fir::factory::getCharacterProcedureTupleType(funcType);
1246764f95a8SValentin Clement       llvm::StringRef charProcAttr = fir::getCharacterProcedureDummyAttrName();
1247764f95a8SValentin Clement       addFirOperand(tupleType, nextPassedArgPosition(), Property::CharProcTuple,
1248764f95a8SValentin Clement                     {mlir::NamedAttribute{
1249764f95a8SValentin Clement                         mlir::StringAttr::get(&mlirContext, charProcAttr),
1250764f95a8SValentin Clement                         mlir::UnitAttr::get(&mlirContext)}});
1251764f95a8SValentin Clement       addPassedArg(PassEntityBy::CharProcTuple, entity, characteristics);
1252764f95a8SValentin Clement       return;
1253764f95a8SValentin Clement     }
1254764f95a8SValentin Clement     addFirOperand(funcType, nextPassedArgPosition(), Property::BaseAddress);
1255764f95a8SValentin Clement     addPassedArg(PassEntityBy::BaseAddress, entity, characteristics);
1256da7c77b8SValentin Clement   }
1257da7c77b8SValentin Clement 
1258764f95a8SValentin Clement   void handleExplicitResult(
1259764f95a8SValentin Clement       const Fortran::evaluate::characteristics::FunctionResult &result) {
1260764f95a8SValentin Clement     using Attr = Fortran::evaluate::characteristics::FunctionResult::Attr;
1261af09219eSDaniel Chen     mlir::Type mlirType;
1262cdb320b4SDaniel Chen     if (auto proc{result.IsProcedurePointer()}) {
1263af09219eSDaniel Chen       mlirType = fir::BoxProcType::get(
1264af09219eSDaniel Chen           &mlirContext, getProcedureType(*proc, interface.converter));
1265cdb320b4SDaniel Chen       addFirResult(mlirType, FirPlaceHolder::resultEntityPosition,
1266cdb320b4SDaniel Chen                    Property::Value);
1267cdb320b4SDaniel Chen       return;
1268cdb320b4SDaniel Chen     }
1269764f95a8SValentin Clement     const Fortran::evaluate::characteristics::TypeAndShape *typeAndShape =
1270764f95a8SValentin Clement         result.GetTypeAndShape();
1271764f95a8SValentin Clement     assert(typeAndShape && "expect type for non proc pointer result");
1272af09219eSDaniel Chen     mlirType = translateDynamicType(typeAndShape->type());
12739d99b482SValentin Clement     const auto *resTypeAndShape{result.GetTypeAndShape()};
12749d99b482SValentin Clement     bool resIsPolymorphic =
12759d99b482SValentin Clement         resTypeAndShape && resTypeAndShape->type().IsPolymorphic();
12763eef2c2bSValentin Clement     bool resIsAssumedType =
12773eef2c2bSValentin Clement         resTypeAndShape && resTypeAndShape->type().IsAssumedType();
1278a49f630cSjeanPerier     if (std::optional<fir::SequenceType::Shape> bounds =
1279a49f630cSjeanPerier             getBounds(*typeAndShape))
1280a49f630cSjeanPerier       mlirType = fir::SequenceType::get(*bounds, mlirType);
1281764f95a8SValentin Clement     if (result.attrs.test(Attr::Allocatable))
1282cdb320b4SDaniel Chen       mlirType = fir::wrapInClassOrBoxType(fir::HeapType::get(mlirType),
1283cdb320b4SDaniel Chen                                            resIsPolymorphic, resIsAssumedType);
1284764f95a8SValentin Clement     if (result.attrs.test(Attr::Pointer))
1285cdb320b4SDaniel Chen       mlirType = fir::wrapInClassOrBoxType(fir::PointerType::get(mlirType),
12863eef2c2bSValentin Clement                                            resIsPolymorphic, resIsAssumedType);
1287764f95a8SValentin Clement 
1288764f95a8SValentin Clement     if (fir::isa_char(mlirType)) {
1289764f95a8SValentin Clement       // Character scalar results must be passed as arguments in lowering so
1290af09219eSDaniel Chen       // that an assumed length character function callee can access the
1291af09219eSDaniel Chen       // result length. A function with a result requiring an explicit
1292af09219eSDaniel Chen       // interface does not have to be compatible with assumed length
1293af09219eSDaniel Chen       // function, but most compilers supports it.
1294764f95a8SValentin Clement       handleImplicitCharacterResult(typeAndShape->type());
1295764f95a8SValentin Clement       return;
1296764f95a8SValentin Clement     }
1297764f95a8SValentin Clement 
1298764f95a8SValentin Clement     addFirResult(mlirType, FirPlaceHolder::resultEntityPosition,
1299764f95a8SValentin Clement                  Property::Value);
1300764f95a8SValentin Clement     // Explicit results require the caller to allocate the storage and save the
1301764f95a8SValentin Clement     // function result in the storage with a fir.save_result.
1302764f95a8SValentin Clement     setSaveResult();
1303764f95a8SValentin Clement   }
1304764f95a8SValentin Clement 
1305a49f630cSjeanPerier   // Return nullopt for scalars, empty vector for assumed rank, and a vector
1306a49f630cSjeanPerier   // with the shape (may contain unknown extents) for arrays.
1307a49f630cSjeanPerier   std::optional<fir::SequenceType::Shape> getBounds(
1308a49f630cSjeanPerier       const Fortran::evaluate::characteristics::TypeAndShape &typeAndShape) {
130973cf0142SjeanPerier     if (typeAndShape.shape() && typeAndShape.shape()->empty())
1310a49f630cSjeanPerier       return std::nullopt;
1311764f95a8SValentin Clement     fir::SequenceType::Shape bounds;
131273cf0142SjeanPerier     if (typeAndShape.shape())
1313a49f630cSjeanPerier       for (const std::optional<Fortran::evaluate::ExtentExpr> &extent :
131473cf0142SjeanPerier            *typeAndShape.shape()) {
1315764f95a8SValentin Clement         fir::SequenceType::Extent bound = fir::SequenceType::getUnknownExtent();
1316764f95a8SValentin Clement         if (std::optional<std::int64_t> i = toInt64(extent))
1317764f95a8SValentin Clement           bound = *i;
1318764f95a8SValentin Clement         bounds.emplace_back(bound);
1319764f95a8SValentin Clement       }
1320764f95a8SValentin Clement     return bounds;
1321764f95a8SValentin Clement   }
1322764f95a8SValentin Clement   std::optional<std::int64_t>
1323764f95a8SValentin Clement   toInt64(std::optional<
1324764f95a8SValentin Clement           Fortran::evaluate::Expr<Fortran::evaluate::SubscriptInteger>>
1325764f95a8SValentin Clement               expr) {
1326764f95a8SValentin Clement     if (expr)
1327764f95a8SValentin Clement       return Fortran::evaluate::ToInt64(Fortran::evaluate::Fold(
1328764f95a8SValentin Clement           getConverter().getFoldingContext(), toEvExpr(*expr)));
1329764f95a8SValentin Clement     return std::nullopt;
1330764f95a8SValentin Clement   }
13319a417395SKazu Hirata   void addFirOperand(
13329a417395SKazu Hirata       mlir::Type type, int entityPosition, Property p,
13339a417395SKazu Hirata       llvm::ArrayRef<mlir::NamedAttribute> attributes = std::nullopt) {
1334da7c77b8SValentin Clement     interface.inputs.emplace_back(
1335da7c77b8SValentin Clement         FirPlaceHolder{type, entityPosition, p, attributes});
1336da7c77b8SValentin Clement   }
1337da7c77b8SValentin Clement   void
1338da7c77b8SValentin Clement   addFirResult(mlir::Type type, int entityPosition, Property p,
13399a417395SKazu Hirata                llvm::ArrayRef<mlir::NamedAttribute> attributes = std::nullopt) {
1340da7c77b8SValentin Clement     interface.outputs.emplace_back(
1341da7c77b8SValentin Clement         FirPlaceHolder{type, entityPosition, p, attributes});
1342da7c77b8SValentin Clement   }
1343da7c77b8SValentin Clement   void addPassedArg(PassEntityBy p, FortranEntity entity,
1344da7c77b8SValentin Clement                     const DummyCharacteristics *characteristics) {
1345da7c77b8SValentin Clement     interface.passedArguments.emplace_back(
1346764f95a8SValentin Clement         PassedEntity{p, entity, emptyValue(), emptyValue(), characteristics});
1347da7c77b8SValentin Clement   }
134837e84d9bSValentin Clement   void setPassedResult(PassEntityBy p, FortranEntity entity) {
134937e84d9bSValentin Clement     interface.passedResult =
135037e84d9bSValentin Clement         PassedEntity{p, entity, emptyValue(), emptyValue()};
135137e84d9bSValentin Clement   }
135237e84d9bSValentin Clement   void setSaveResult() { interface.saveResult = true; }
1353da7c77b8SValentin Clement   int nextPassedArgPosition() { return interface.passedArguments.size(); }
1354ad40cc14SValentin Clement 
135537e84d9bSValentin Clement   static FirValue emptyValue() {
135637e84d9bSValentin Clement     if constexpr (std::is_same_v<Fortran::lower::CalleeInterface, T>) {
135737e84d9bSValentin Clement       return {};
135837e84d9bSValentin Clement     } else {
135937e84d9bSValentin Clement       return -1;
136037e84d9bSValentin Clement     }
136137e84d9bSValentin Clement   }
136237e84d9bSValentin Clement 
1363ad40cc14SValentin Clement   Fortran::lower::AbstractConverter &getConverter() {
1364ad40cc14SValentin Clement     return interface.converter;
1365ad40cc14SValentin Clement   }
1366ad40cc14SValentin Clement   CallInterface &interface;
1367ad40cc14SValentin Clement   mlir::MLIRContext &mlirContext;
1368ad40cc14SValentin Clement };
1369ad40cc14SValentin Clement 
1370ad40cc14SValentin Clement template <typename T>
1371d0b70a07SValentin Clement bool Fortran::lower::CallInterface<T>::PassedEntity::isOptional() const {
1372d0b70a07SValentin Clement   if (!characteristics)
1373d0b70a07SValentin Clement     return false;
1374d0b70a07SValentin Clement   return characteristics->IsOptional();
1375d0b70a07SValentin Clement }
1376d0b70a07SValentin Clement template <typename T>
1377d0b70a07SValentin Clement bool Fortran::lower::CallInterface<T>::PassedEntity::mayBeModifiedByCall()
1378d0b70a07SValentin Clement     const {
1379d0b70a07SValentin Clement   if (!characteristics)
1380d0b70a07SValentin Clement     return true;
13814203b062SJean Perier   if (characteristics->GetIntent() == Fortran::common::Intent::In)
13824203b062SJean Perier     return false;
138387cd6f93SJean Perier   return !hasValueAttribute();
1384d0b70a07SValentin Clement }
1385d0b70a07SValentin Clement template <typename T>
1386d0b70a07SValentin Clement bool Fortran::lower::CallInterface<T>::PassedEntity::mayBeReadByCall() const {
1387d0b70a07SValentin Clement   if (!characteristics)
1388d0b70a07SValentin Clement     return true;
1389d0b70a07SValentin Clement   return characteristics->GetIntent() != Fortran::common::Intent::Out;
1390d0b70a07SValentin Clement }
1391f5dbee00SSlava Zakharin 
1392f5dbee00SSlava Zakharin template <typename T>
1393f5dbee00SSlava Zakharin bool Fortran::lower::CallInterface<T>::PassedEntity::testTKR(
1394f5dbee00SSlava Zakharin     Fortran::common::IgnoreTKR flag) const {
1395f5dbee00SSlava Zakharin   if (!characteristics)
1396f5dbee00SSlava Zakharin     return false;
1397f5dbee00SSlava Zakharin   const auto *dummy =
1398f5dbee00SSlava Zakharin       std::get_if<Fortran::evaluate::characteristics::DummyDataObject>(
1399f5dbee00SSlava Zakharin           &characteristics->u);
1400f5dbee00SSlava Zakharin   if (!dummy)
1401f5dbee00SSlava Zakharin     return false;
1402f5dbee00SSlava Zakharin   return dummy->ignoreTKR.test(flag);
1403f5dbee00SSlava Zakharin }
1404f5dbee00SSlava Zakharin 
1405273b3350SValentin Clement template <typename T>
1406273b3350SValentin Clement bool Fortran::lower::CallInterface<T>::PassedEntity::isIntentOut() const {
1407273b3350SValentin Clement   if (!characteristics)
1408273b3350SValentin Clement     return true;
1409273b3350SValentin Clement   return characteristics->GetIntent() == Fortran::common::Intent::Out;
1410273b3350SValentin Clement }
14115ac8cc68SJean Perier template <typename T>
14125ac8cc68SJean Perier bool Fortran::lower::CallInterface<T>::PassedEntity::mustBeMadeContiguous()
14135ac8cc68SJean Perier     const {
14145ac8cc68SJean Perier   if (!characteristics)
14155ac8cc68SJean Perier     return true;
14165ac8cc68SJean Perier   const auto *dummy =
14175ac8cc68SJean Perier       std::get_if<Fortran::evaluate::characteristics::DummyDataObject>(
14185ac8cc68SJean Perier           &characteristics->u);
14195ac8cc68SJean Perier   if (!dummy)
14205ac8cc68SJean Perier     return false;
14215ac8cc68SJean Perier   const auto &shapeAttrs = dummy->type.attrs();
14225ac8cc68SJean Perier   using ShapeAttrs = Fortran::evaluate::characteristics::TypeAndShape::Attr;
14235ac8cc68SJean Perier   if (shapeAttrs.test(ShapeAttrs::AssumedRank) ||
14245ac8cc68SJean Perier       shapeAttrs.test(ShapeAttrs::AssumedShape))
14255ac8cc68SJean Perier     return dummy->attrs.test(
14265ac8cc68SJean Perier         Fortran::evaluate::characteristics::DummyDataObject::Attr::Contiguous);
14275ac8cc68SJean Perier   if (shapeAttrs.test(ShapeAttrs::DeferredShape))
14285ac8cc68SJean Perier     return false;
14295ac8cc68SJean Perier   // Explicit shape arrays are contiguous.
14305ac8cc68SJean Perier   return dummy->type.Rank() > 0;
14315ac8cc68SJean Perier }
1432d0b70a07SValentin Clement 
1433d0b70a07SValentin Clement template <typename T>
143487cd6f93SJean Perier bool Fortran::lower::CallInterface<T>::PassedEntity::hasValueAttribute() const {
143587cd6f93SJean Perier   if (!characteristics)
143687cd6f93SJean Perier     return false;
143787cd6f93SJean Perier   const auto *dummy =
143887cd6f93SJean Perier       std::get_if<Fortran::evaluate::characteristics::DummyDataObject>(
143987cd6f93SJean Perier           &characteristics->u);
144087cd6f93SJean Perier   return dummy &&
144187cd6f93SJean Perier          dummy->attrs.test(
144287cd6f93SJean Perier              Fortran::evaluate::characteristics::DummyDataObject::Attr::Value);
144387cd6f93SJean Perier }
144487cd6f93SJean Perier 
144587cd6f93SJean Perier template <typename T>
1446da60b9e7SSlava Zakharin bool Fortran::lower::CallInterface<T>::PassedEntity::hasAllocatableAttribute()
1447da60b9e7SSlava Zakharin     const {
1448da60b9e7SSlava Zakharin   if (!characteristics)
1449da60b9e7SSlava Zakharin     return false;
1450da60b9e7SSlava Zakharin   const auto *dummy =
1451da60b9e7SSlava Zakharin       std::get_if<Fortran::evaluate::characteristics::DummyDataObject>(
1452da60b9e7SSlava Zakharin           &characteristics->u);
1453da60b9e7SSlava Zakharin   using Attrs = Fortran::evaluate::characteristics::DummyDataObject::Attr;
1454da60b9e7SSlava Zakharin   return dummy && dummy->attrs.test(Attrs::Allocatable);
1455da60b9e7SSlava Zakharin }
1456da60b9e7SSlava Zakharin 
1457da60b9e7SSlava Zakharin template <typename T>
1458da60b9e7SSlava Zakharin bool Fortran::lower::CallInterface<
1459da60b9e7SSlava Zakharin     T>::PassedEntity::mayRequireIntentoutFinalization() const {
1460da60b9e7SSlava Zakharin   // Conservatively assume that the finalization is needed.
1461da60b9e7SSlava Zakharin   if (!characteristics)
1462da60b9e7SSlava Zakharin     return true;
1463da60b9e7SSlava Zakharin 
1464da60b9e7SSlava Zakharin   // No INTENT(OUT) dummy arguments do not require finalization on entry.
1465da60b9e7SSlava Zakharin   if (!isIntentOut())
1466da60b9e7SSlava Zakharin     return false;
1467da60b9e7SSlava Zakharin 
1468da60b9e7SSlava Zakharin   const auto *dummy =
1469da60b9e7SSlava Zakharin       std::get_if<Fortran::evaluate::characteristics::DummyDataObject>(
1470da60b9e7SSlava Zakharin           &characteristics->u);
1471da60b9e7SSlava Zakharin   if (!dummy)
1472da60b9e7SSlava Zakharin     return true;
1473da60b9e7SSlava Zakharin 
1474da60b9e7SSlava Zakharin   // POINTER/ALLOCATABLE dummy arguments do not require finalization.
1475da60b9e7SSlava Zakharin   using Attrs = Fortran::evaluate::characteristics::DummyDataObject::Attr;
1476da60b9e7SSlava Zakharin   if (dummy->attrs.test(Attrs::Allocatable) ||
1477da60b9e7SSlava Zakharin       dummy->attrs.test(Attrs::Pointer))
1478da60b9e7SSlava Zakharin     return false;
1479da60b9e7SSlava Zakharin 
1480da60b9e7SSlava Zakharin   // Polymorphic and unlimited polymorphic INTENT(OUT) dummy arguments
1481da60b9e7SSlava Zakharin   // may need finalization.
1482da60b9e7SSlava Zakharin   const Fortran::evaluate::DynamicType &type = dummy->type.type();
1483da60b9e7SSlava Zakharin   if (type.IsPolymorphic() || type.IsUnlimitedPolymorphic())
1484da60b9e7SSlava Zakharin     return true;
1485da60b9e7SSlava Zakharin 
1486da60b9e7SSlava Zakharin   // INTENT(OUT) dummy arguments of derived types require finalization,
1487da60b9e7SSlava Zakharin   // if their type has finalization.
1488da60b9e7SSlava Zakharin   const Fortran::semantics::DerivedTypeSpec *derived =
1489da60b9e7SSlava Zakharin       Fortran::evaluate::GetDerivedTypeSpec(type);
1490da60b9e7SSlava Zakharin   if (!derived)
1491da60b9e7SSlava Zakharin     return false;
1492da60b9e7SSlava Zakharin 
1493da60b9e7SSlava Zakharin   return Fortran::semantics::IsFinalizable(*derived);
1494da60b9e7SSlava Zakharin }
1495da60b9e7SSlava Zakharin 
1496da60b9e7SSlava Zakharin template <typename T>
14978eee2360SjeanPerier bool Fortran::lower::CallInterface<
14988eee2360SjeanPerier     T>::PassedEntity::isSequenceAssociatedDescriptor() const {
14998eee2360SjeanPerier   if (!characteristics || passBy != PassEntityBy::Box)
15008eee2360SjeanPerier     return false;
15018eee2360SjeanPerier   const auto *dummy =
15028eee2360SjeanPerier       std::get_if<Fortran::evaluate::characteristics::DummyDataObject>(
15038eee2360SjeanPerier           &characteristics->u);
15048eee2360SjeanPerier   return dummy && dummy->type.CanBeSequenceAssociated();
15058eee2360SjeanPerier }
15068eee2360SjeanPerier 
15078eee2360SjeanPerier template <typename T>
1508ad40cc14SValentin Clement void Fortran::lower::CallInterface<T>::determineInterface(
1509ad40cc14SValentin Clement     bool isImplicit,
1510ad40cc14SValentin Clement     const Fortran::evaluate::characteristics::Procedure &procedure) {
1511ad40cc14SValentin Clement   CallInterfaceImpl<T> impl(*this);
1512ad40cc14SValentin Clement   if (isImplicit)
1513ad40cc14SValentin Clement     impl.buildImplicitInterface(procedure);
1514ad40cc14SValentin Clement   else
1515c807aa53SValentin Clement     impl.buildExplicitInterface(procedure);
1516764f95a8SValentin Clement   // We only expect the extra host asspciations argument from the callee side as
1517764f95a8SValentin Clement   // the definition of internal procedures will be present, and we'll always
1518764f95a8SValentin Clement   // have a FuncOp definition in the ModuleOp, when lowering.
1519764f95a8SValentin Clement   if constexpr (std::is_same_v<T, Fortran::lower::CalleeInterface>) {
1520764f95a8SValentin Clement     if (side().hasHostAssociated())
1521764f95a8SValentin Clement       impl.appendHostAssocTupleArg(side().getHostAssociatedTy());
1522764f95a8SValentin Clement   }
1523ad40cc14SValentin Clement }
1524ad40cc14SValentin Clement 
1525e1a12767SValentin Clement template <typename T>
1526e1a12767SValentin Clement mlir::FunctionType Fortran::lower::CallInterface<T>::genFunctionType() {
1527ad40cc14SValentin Clement   llvm::SmallVector<mlir::Type> returnTys;
1528da7c77b8SValentin Clement   llvm::SmallVector<mlir::Type> inputTys;
1529ad40cc14SValentin Clement   for (const FirPlaceHolder &placeHolder : outputs)
1530ad40cc14SValentin Clement     returnTys.emplace_back(placeHolder.type);
1531da7c77b8SValentin Clement   for (const FirPlaceHolder &placeHolder : inputs)
1532da7c77b8SValentin Clement     inputTys.emplace_back(placeHolder.type);
1533da7c77b8SValentin Clement   return mlir::FunctionType::get(&converter.getMLIRContext(), inputTys,
1534da7c77b8SValentin Clement                                  returnTys);
1535e1a12767SValentin Clement }
1536e1a12767SValentin Clement 
1537764f95a8SValentin Clement template <typename T>
1538764f95a8SValentin Clement llvm::SmallVector<mlir::Type>
1539764f95a8SValentin Clement Fortran::lower::CallInterface<T>::getResultType() const {
1540764f95a8SValentin Clement   llvm::SmallVector<mlir::Type> types;
1541764f95a8SValentin Clement   for (const FirPlaceHolder &out : outputs)
1542764f95a8SValentin Clement     types.emplace_back(out.type);
1543764f95a8SValentin Clement   return types;
1544764f95a8SValentin Clement }
1545764f95a8SValentin Clement 
15463be8e3adSjeanPerier template <typename T>
15473be8e3adSjeanPerier fir::FortranProcedureFlagsEnumAttr
15483be8e3adSjeanPerier Fortran::lower::CallInterface<T>::getProcedureAttrs(
15493be8e3adSjeanPerier     mlir::MLIRContext *mlirContext) const {
15503be8e3adSjeanPerier   fir::FortranProcedureFlagsEnum flags = fir::FortranProcedureFlagsEnum::none;
1551d9250061SjeanPerier   if (characteristic) {
15523be8e3adSjeanPerier     if (characteristic->IsBindC())
15533be8e3adSjeanPerier       flags = flags | fir::FortranProcedureFlagsEnum::bind_c;
15543be8e3adSjeanPerier     if (characteristic->IsPure())
15553be8e3adSjeanPerier       flags = flags | fir::FortranProcedureFlagsEnum::pure;
15563be8e3adSjeanPerier     if (characteristic->IsElemental())
15573be8e3adSjeanPerier       flags = flags | fir::FortranProcedureFlagsEnum::elemental;
15583be8e3adSjeanPerier     // TODO:
15593be8e3adSjeanPerier     // - SIMPLE: F2023, not yet handled by semantics.
1560d9250061SjeanPerier   }
1561d9250061SjeanPerier 
1562d9250061SjeanPerier   if constexpr (std::is_same_v<Fortran::lower::CalleeInterface, T>) {
1563d9250061SjeanPerier     // Only gather and set NON_RECURSIVE for procedure definition. It is
1564d9250061SjeanPerier     // meaningless on calls since this is not part of Fortran characteristics
1565d9250061SjeanPerier     // (Fortran 2023 15.3.1) so there is no way to always know if the procedure
1566d9250061SjeanPerier     // called is recursive or not.
1567d9250061SjeanPerier     if (const Fortran::semantics::Symbol *sym = side().getProcedureSymbol()) {
1568d9250061SjeanPerier       // Note: By default procedures are RECURSIVE unless
1569d9250061SjeanPerier       // -fno-automatic/-save/-Msave is set. NON_RECURSIVE is is made explicit
1570d9250061SjeanPerier       // in that case in FIR.
1571d9250061SjeanPerier       if (sym->attrs().test(Fortran::semantics::Attr::NON_RECURSIVE) ||
1572d9250061SjeanPerier           (sym->owner().context().languageFeatures().IsEnabled(
1573d9250061SjeanPerier                Fortran::common::LanguageFeature::DefaultSave) &&
1574d9250061SjeanPerier            !sym->attrs().test(Fortran::semantics::Attr::RECURSIVE))) {
1575d9250061SjeanPerier         flags = flags | fir::FortranProcedureFlagsEnum::non_recursive;
1576d9250061SjeanPerier       }
1577d9250061SjeanPerier     }
1578d9250061SjeanPerier   }
15793be8e3adSjeanPerier   if (flags != fir::FortranProcedureFlagsEnum::none)
15803be8e3adSjeanPerier     return fir::FortranProcedureFlagsEnumAttr::get(mlirContext, flags);
15813be8e3adSjeanPerier   return nullptr;
15823be8e3adSjeanPerier }
15833be8e3adSjeanPerier 
1584e1a12767SValentin Clement template class Fortran::lower::CallInterface<Fortran::lower::CalleeInterface>;
1585d0b70a07SValentin Clement template class Fortran::lower::CallInterface<Fortran::lower::CallerInterface>;
1586764f95a8SValentin Clement 
1587764f95a8SValentin Clement //===----------------------------------------------------------------------===//
1588764f95a8SValentin Clement // Function Type Translation
1589764f95a8SValentin Clement //===----------------------------------------------------------------------===//
1590764f95a8SValentin Clement 
1591764f95a8SValentin Clement /// Build signature from characteristics when there is no Fortran entity to
1592764f95a8SValentin Clement /// associate with the arguments (i.e, this is not a call site or a procedure
1593764f95a8SValentin Clement /// declaration. This is needed when dealing with function pointers/dummy
1594764f95a8SValentin Clement /// arguments.
1595764f95a8SValentin Clement 
1596764f95a8SValentin Clement class SignatureBuilder;
1597764f95a8SValentin Clement template <>
1598764f95a8SValentin Clement struct Fortran::lower::PassedEntityTypes<SignatureBuilder> {
1599764f95a8SValentin Clement   using FortranEntity = FakeEntity;
1600764f95a8SValentin Clement   using FirValue = int;
1601764f95a8SValentin Clement };
1602764f95a8SValentin Clement 
1603764f95a8SValentin Clement /// SignatureBuilder is a CRTP implementation of CallInterface intended to
1604764f95a8SValentin Clement /// help translating characteristics::Procedure to mlir::FunctionType using
1605764f95a8SValentin Clement /// the CallInterface translation.
1606764f95a8SValentin Clement class SignatureBuilder
1607764f95a8SValentin Clement     : public Fortran::lower::CallInterface<SignatureBuilder> {
1608764f95a8SValentin Clement public:
1609764f95a8SValentin Clement   SignatureBuilder(const Fortran::evaluate::characteristics::Procedure &p,
1610764f95a8SValentin Clement                    Fortran::lower::AbstractConverter &c, bool forceImplicit)
1611764f95a8SValentin Clement       : CallInterface{c}, proc{p} {
1612764f95a8SValentin Clement     bool isImplicit = forceImplicit || proc.CanBeCalledViaImplicitInterface();
1613764f95a8SValentin Clement     determineInterface(isImplicit, proc);
1614764f95a8SValentin Clement   }
161588684317SjeanPerier   SignatureBuilder(const Fortran::evaluate::ProcedureDesignator &procDes,
161688684317SjeanPerier                    Fortran::lower::AbstractConverter &c)
161788684317SjeanPerier       : CallInterface{c}, procDesignator{&procDes},
161888684317SjeanPerier         proc{Fortran::evaluate::characteristics::Procedure::Characterize(
1619cb263919SPeter Klausler                  procDes, converter.getFoldingContext(), /*emitError=*/false)
162088684317SjeanPerier                  .value()} {}
1621764f95a8SValentin Clement   /// Does the procedure characteristics being translated have alternate
1622764f95a8SValentin Clement   /// returns ?
1623764f95a8SValentin Clement   bool hasAlternateReturns() const {
1624764f95a8SValentin Clement     for (const Fortran::evaluate::characteristics::DummyArgument &dummy :
1625764f95a8SValentin Clement          proc.dummyArguments)
1626764f95a8SValentin Clement       if (std::holds_alternative<
1627764f95a8SValentin Clement               Fortran::evaluate::characteristics::AlternateReturn>(dummy.u))
1628764f95a8SValentin Clement         return true;
1629764f95a8SValentin Clement     return false;
1630764f95a8SValentin Clement   };
1631764f95a8SValentin Clement 
1632764f95a8SValentin Clement   /// This is only here to fulfill CRTP dependencies and should not be called.
1633764f95a8SValentin Clement   std::string getMangledName() const {
163488684317SjeanPerier     if (procDesignator)
163588684317SjeanPerier       return getProcMangledName(*procDesignator, converter);
163688684317SjeanPerier     fir::emitFatalError(
163788684317SjeanPerier         converter.getCurrentLocation(),
163888684317SjeanPerier         "should not query name when only building function type");
1639764f95a8SValentin Clement   }
1640764f95a8SValentin Clement 
1641764f95a8SValentin Clement   /// This is only here to fulfill CRTP dependencies and should not be called.
1642764f95a8SValentin Clement   mlir::Location getCalleeLocation() const {
164388684317SjeanPerier     if (procDesignator)
164488684317SjeanPerier       return getProcedureDesignatorLoc(*procDesignator, converter);
164588684317SjeanPerier     return converter.getCurrentLocation();
1646764f95a8SValentin Clement   }
1647764f95a8SValentin Clement 
1648764f95a8SValentin Clement   const Fortran::semantics::Symbol *getProcedureSymbol() const {
164988684317SjeanPerier     if (procDesignator)
165088684317SjeanPerier       return procDesignator->GetSymbol();
165188684317SjeanPerier     return nullptr;
1652764f95a8SValentin Clement   };
1653764f95a8SValentin Clement 
1654764f95a8SValentin Clement   Fortran::evaluate::characteristics::Procedure characterize() const {
1655764f95a8SValentin Clement     return proc;
1656764f95a8SValentin Clement   }
1657764f95a8SValentin Clement   /// SignatureBuilder cannot be used on main program.
1658764f95a8SValentin Clement   static constexpr bool isMainProgram() { return false; }
1659764f95a8SValentin Clement 
1660764f95a8SValentin Clement   /// Return the characteristics::Procedure that is being translated to
1661764f95a8SValentin Clement   /// mlir::FunctionType.
1662764f95a8SValentin Clement   const Fortran::evaluate::characteristics::Procedure &
1663764f95a8SValentin Clement   getCallDescription() const {
1664764f95a8SValentin Clement     return proc;
1665764f95a8SValentin Clement   }
1666764f95a8SValentin Clement 
1667764f95a8SValentin Clement   /// This is not the description of an indirect call.
1668764f95a8SValentin Clement   static constexpr bool isIndirectCall() { return false; }
1669764f95a8SValentin Clement 
1670764f95a8SValentin Clement   /// Return the translated signature.
167188684317SjeanPerier   mlir::FunctionType getFunctionType() {
167288684317SjeanPerier     if (interfaceDetermined)
167388684317SjeanPerier       fir::emitFatalError(converter.getCurrentLocation(),
167488684317SjeanPerier                           "SignatureBuilder should only be used once");
167588684317SjeanPerier     // Most unrestricted intrinsic characteristics have the Elemental attribute
167688684317SjeanPerier     // which triggers CanBeCalledViaImplicitInterface to return false. However,
167788684317SjeanPerier     // using implicit interface rules is just fine here.
167888684317SjeanPerier     bool forceImplicit =
167988684317SjeanPerier         procDesignator && procDesignator->GetSpecificIntrinsic();
168088684317SjeanPerier     bool isImplicit = forceImplicit || proc.CanBeCalledViaImplicitInterface();
168188684317SjeanPerier     determineInterface(isImplicit, proc);
168288684317SjeanPerier     interfaceDetermined = true;
168388684317SjeanPerier     return genFunctionType();
168488684317SjeanPerier   }
168588684317SjeanPerier 
168688684317SjeanPerier   mlir::func::FuncOp getOrCreateFuncOp() {
168788684317SjeanPerier     if (interfaceDetermined)
168888684317SjeanPerier       fir::emitFatalError(converter.getCurrentLocation(),
168988684317SjeanPerier                           "SignatureBuilder should only be used once");
169088684317SjeanPerier     declare();
169188684317SjeanPerier     interfaceDetermined = true;
169288684317SjeanPerier     return getFuncOp();
169388684317SjeanPerier   }
1694764f95a8SValentin Clement 
1695764f95a8SValentin Clement   // Copy of base implementation.
1696764f95a8SValentin Clement   static constexpr bool hasHostAssociated() { return false; }
1697764f95a8SValentin Clement   mlir::Type getHostAssociatedTy() const {
1698764f95a8SValentin Clement     llvm_unreachable("getting host associated type in SignatureBuilder");
1699764f95a8SValentin Clement   }
1700764f95a8SValentin Clement 
1701764f95a8SValentin Clement private:
170288684317SjeanPerier   const Fortran::evaluate::ProcedureDesignator *procDesignator = nullptr;
170388684317SjeanPerier   Fortran::evaluate::characteristics::Procedure proc;
170488684317SjeanPerier   bool interfaceDetermined = false;
1705764f95a8SValentin Clement };
1706764f95a8SValentin Clement 
1707764f95a8SValentin Clement mlir::FunctionType Fortran::lower::translateSignature(
1708764f95a8SValentin Clement     const Fortran::evaluate::ProcedureDesignator &proc,
1709764f95a8SValentin Clement     Fortran::lower::AbstractConverter &converter) {
171088684317SjeanPerier   return SignatureBuilder{proc, converter}.getFunctionType();
1711764f95a8SValentin Clement }
1712764f95a8SValentin Clement 
171358ceae95SRiver Riddle mlir::func::FuncOp Fortran::lower::getOrDeclareFunction(
171488684317SjeanPerier     const Fortran::evaluate::ProcedureDesignator &proc,
1715764f95a8SValentin Clement     Fortran::lower::AbstractConverter &converter) {
1716764f95a8SValentin Clement   mlir::ModuleOp module = converter.getModuleOp();
171788684317SjeanPerier   std::string name = getProcMangledName(proc, converter);
1718a4798bb0SjeanPerier   mlir::func::FuncOp func = fir::FirOpBuilder::getNamedFunction(
1719a4798bb0SjeanPerier       module, converter.getMLIRSymbolTable(), name);
1720764f95a8SValentin Clement   if (func)
1721764f95a8SValentin Clement     return func;
1722764f95a8SValentin Clement 
1723764f95a8SValentin Clement   // getOrDeclareFunction is only used for functions not defined in the current
1724764f95a8SValentin Clement   // program unit, so use the location of the procedure designator symbol, which
1725764f95a8SValentin Clement   // is the first occurrence of the procedure in the program unit.
172688684317SjeanPerier   return SignatureBuilder{proc, converter}.getOrCreateFuncOp();
1727764f95a8SValentin Clement }
1728764f95a8SValentin Clement 
1729764f95a8SValentin Clement // Is it required to pass a dummy procedure with \p characteristics as a tuple
1730764f95a8SValentin Clement // containing the function address and the result length ?
1731764f95a8SValentin Clement static bool mustPassLengthWithDummyProcedure(
1732764f95a8SValentin Clement     const std::optional<Fortran::evaluate::characteristics::Procedure>
1733764f95a8SValentin Clement         &characteristics) {
1734764f95a8SValentin Clement   return characteristics &&
1735764f95a8SValentin Clement          Fortran::lower::CallInterfaceImpl<SignatureBuilder>::
1736764f95a8SValentin Clement              mustPassLengthWithDummyProcedure(*characteristics);
1737764f95a8SValentin Clement }
1738764f95a8SValentin Clement 
1739764f95a8SValentin Clement bool Fortran::lower::mustPassLengthWithDummyProcedure(
1740764f95a8SValentin Clement     const Fortran::evaluate::ProcedureDesignator &procedure,
1741764f95a8SValentin Clement     Fortran::lower::AbstractConverter &converter) {
1742764f95a8SValentin Clement   std::optional<Fortran::evaluate::characteristics::Procedure> characteristics =
1743764f95a8SValentin Clement       Fortran::evaluate::characteristics::Procedure::Characterize(
1744cb263919SPeter Klausler           procedure, converter.getFoldingContext(), /*emitError=*/false);
1745764f95a8SValentin Clement   return ::mustPassLengthWithDummyProcedure(characteristics);
1746764f95a8SValentin Clement }
1747764f95a8SValentin Clement 
1748764f95a8SValentin Clement mlir::Type Fortran::lower::getDummyProcedureType(
1749764f95a8SValentin Clement     const Fortran::semantics::Symbol &dummyProc,
1750764f95a8SValentin Clement     Fortran::lower::AbstractConverter &converter) {
1751764f95a8SValentin Clement   std::optional<Fortran::evaluate::characteristics::Procedure> iface =
1752764f95a8SValentin Clement       Fortran::evaluate::characteristics::Procedure::Characterize(
1753764f95a8SValentin Clement           dummyProc, converter.getFoldingContext());
1754764f95a8SValentin Clement   mlir::Type procType = getProcedureDesignatorType(
1755764f95a8SValentin Clement       iface.has_value() ? &*iface : nullptr, converter);
1756764f95a8SValentin Clement   if (::mustPassLengthWithDummyProcedure(iface))
1757764f95a8SValentin Clement     return fir::factory::getCharacterProcedureTupleType(procType);
1758764f95a8SValentin Clement   return procType;
1759764f95a8SValentin Clement }
17604943dbdfSPeixin Qiao 
17614943dbdfSPeixin Qiao bool Fortran::lower::isCPtrArgByValueType(mlir::Type ty) {
1762fac349a1SChristian Sigg   return mlir::isa<fir::ReferenceType>(ty) &&
17634943dbdfSPeixin Qiao          fir::isa_integer(fir::unwrapRefType(ty));
17644943dbdfSPeixin Qiao }
1765af09219eSDaniel Chen 
1766af09219eSDaniel Chen // Return the mlir::FunctionType of a procedure
1767af09219eSDaniel Chen static mlir::FunctionType
1768af09219eSDaniel Chen getProcedureType(const Fortran::evaluate::characteristics::Procedure &proc,
1769af09219eSDaniel Chen                  Fortran::lower::AbstractConverter &converter) {
1770af09219eSDaniel Chen   return SignatureBuilder{proc, converter, false}.genFunctionType();
1771af09219eSDaniel Chen }
1772