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