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