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