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