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