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/Support/Utils.h" 15 #include "flang/Optimizer/Builder/FIRBuilder.h" 16 #include "flang/Optimizer/Dialect/FIRDialect.h" 17 #include "flang/Optimizer/Dialect/FIROpsSupport.h" 18 #include "flang/Optimizer/Support/InternalNames.h" 19 #include "flang/Semantics/symbol.h" 20 #include "flang/Semantics/tools.h" 21 22 //===----------------------------------------------------------------------===// 23 // BIND(C) mangling helpers 24 //===----------------------------------------------------------------------===// 25 26 // Return the binding label (from BIND(C...)) or the mangled name of a symbol. 27 static std::string getMangledName(const Fortran::semantics::Symbol &symbol) { 28 const std::string *bindName = symbol.GetBindName(); 29 return bindName ? *bindName : Fortran::lower::mangle::mangleName(symbol); 30 } 31 32 //===----------------------------------------------------------------------===// 33 // Callee side interface implementation 34 //===----------------------------------------------------------------------===// 35 36 std::string Fortran::lower::CalleeInterface::getMangledName() const { 37 if (funit.isMainProgram()) 38 return fir::NameUniquer::doProgramEntry().str(); 39 return ::getMangledName(funit.getSubprogramSymbol()); 40 } 41 42 const Fortran::semantics::Symbol * 43 Fortran::lower::CalleeInterface::getProcedureSymbol() const { 44 if (funit.isMainProgram()) 45 return nullptr; 46 return &funit.getSubprogramSymbol(); 47 } 48 49 mlir::Location Fortran::lower::CalleeInterface::getCalleeLocation() const { 50 // FIXME: do NOT use unknown for the anonymous PROGRAM case. We probably 51 // should just stash the location in the funit regardless. 52 return converter.genLocation(funit.getStartingSourceLoc()); 53 } 54 55 mlir::FuncOp Fortran::lower::CalleeInterface::addEntryBlockAndMapArguments() { 56 // On the callee side, directly map the mlir::value argument of 57 // the function block to the Fortran symbols. 58 func.addEntryBlock(); 59 return func; 60 } 61 62 //===----------------------------------------------------------------------===// 63 // CallInterface implementation: this part is common to both callee and caller 64 // sides. 65 //===----------------------------------------------------------------------===// 66 67 static void addSymbolAttribute(mlir::FuncOp func, 68 const Fortran::semantics::Symbol &sym, 69 mlir::MLIRContext &mlirContext) { 70 // Only add this on bind(C) functions for which the symbol is not reflected in 71 // the current context. 72 if (!Fortran::semantics::IsBindCProcedure(sym)) 73 return; 74 std::string name = 75 Fortran::lower::mangle::mangleName(sym, /*keepExternalInScope=*/true); 76 func->setAttr(fir::getSymbolAttrName(), 77 mlir::StringAttr::get(&mlirContext, name)); 78 } 79 80 /// Declare drives the different actions to be performed while analyzing the 81 /// signature and building/finding the mlir::FuncOp. 82 template <typename T> 83 void Fortran::lower::CallInterface<T>::declare() { 84 // Create / get funcOp for direct calls. For indirect calls (only meaningful 85 // on the caller side), no funcOp has to be created here. The mlir::Value 86 // holding the indirection is used when creating the fir::CallOp. 87 if (!side().isIndirectCall()) { 88 std::string name = side().getMangledName(); 89 mlir::ModuleOp module = converter.getModuleOp(); 90 func = fir::FirOpBuilder::getNamedFunction(module, name); 91 if (!func) { 92 mlir::Location loc = side().getCalleeLocation(); 93 mlir::FunctionType ty = genFunctionType(); 94 func = fir::FirOpBuilder::createFunction(loc, module, name, ty); 95 if (const Fortran::semantics::Symbol *sym = side().getProcedureSymbol()) 96 addSymbolAttribute(func, *sym, converter.getMLIRContext()); 97 } 98 } 99 } 100 101 template <typename T> 102 mlir::FunctionType Fortran::lower::CallInterface<T>::genFunctionType() { 103 return mlir::FunctionType::get(&converter.getMLIRContext(), {}, {}); 104 } 105 106 template class Fortran::lower::CallInterface<Fortran::lower::CalleeInterface>; 107