1 //===-- ConvertVariable.cpp -- bridge to lower to MLIR --------------------===//
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 // Coding style: https://mlir.llvm.org/getting_started/DeveloperGuide/
10 //
11 //===----------------------------------------------------------------------===//
12 
13 #include "flang/Lower/ConvertVariable.h"
14 #include "flang/Lower/AbstractConverter.h"
15 #include "flang/Lower/CallInterface.h"
16 #include "flang/Lower/ConvertExpr.h"
17 #include "flang/Lower/Mangler.h"
18 #include "flang/Lower/PFTBuilder.h"
19 #include "flang/Lower/Support/Utils.h"
20 #include "flang/Lower/SymbolMap.h"
21 #include "flang/Lower/Todo.h"
22 #include "flang/Optimizer/Builder/Character.h"
23 #include "flang/Optimizer/Builder/FIRBuilder.h"
24 #include "flang/Optimizer/Builder/Runtime/Derived.h"
25 #include "flang/Optimizer/Dialect/FIRAttr.h"
26 #include "flang/Optimizer/Dialect/FIRDialect.h"
27 #include "flang/Optimizer/Dialect/FIROps.h"
28 #include "flang/Optimizer/Support/FIRContext.h"
29 #include "flang/Optimizer/Support/FatalError.h"
30 #include "flang/Semantics/tools.h"
31 #include "llvm/Support/Debug.h"
32 
33 #define DEBUG_TYPE "flang-lower-variable"
34 
35 //===----------------------------------------------------------------===//
36 // Local variables instantiation (not for alias)
37 //===----------------------------------------------------------------===//
38 
39 /// Create a stack slot for a local variable. Precondition: the insertion
40 /// point of the builder must be in the entry block, which is currently being
41 /// constructed.
42 static mlir::Value createNewLocal(Fortran::lower::AbstractConverter &converter,
43                                   mlir::Location loc,
44                                   const Fortran::lower::pft::Variable &var,
45                                   mlir::Value preAlloc,
46                                   llvm::ArrayRef<mlir::Value> shape = {},
47                                   llvm::ArrayRef<mlir::Value> lenParams = {}) {
48   if (preAlloc)
49     return preAlloc;
50   fir::FirOpBuilder &builder = converter.getFirOpBuilder();
51   std::string nm = Fortran::lower::mangle::mangleName(var.getSymbol());
52   mlir::Type ty = converter.genType(var);
53   const Fortran::semantics::Symbol &ultimateSymbol =
54       var.getSymbol().GetUltimate();
55   llvm::StringRef symNm = toStringRef(ultimateSymbol.name());
56   bool isTarg = var.isTarget();
57   // Let the builder do all the heavy lifting.
58   return builder.allocateLocal(loc, ty, nm, symNm, shape, lenParams, isTarg);
59 }
60 
61 /// Instantiate a local variable. Precondition: Each variable will be visited
62 /// such that if its properties depend on other variables, the variables upon
63 /// which its properties depend will already have been visited.
64 static void instantiateLocal(Fortran::lower::AbstractConverter &converter,
65                              const Fortran::lower::pft::Variable &var,
66                              Fortran::lower::SymMap &symMap) {
67   assert(!var.isAlias());
68   const Fortran::semantics::Symbol &sym = var.getSymbol();
69   const bool isDummy = Fortran::semantics::IsDummy(sym);
70   const bool isResult = Fortran::semantics::IsFunctionResult(sym);
71   if (symMap.lookupSymbol(sym))
72     return;
73 
74   const mlir::Location loc = converter.genLocation(sym.name());
75   if (isDummy) {
76     // This is an argument.
77     if (!symMap.lookupSymbol(sym))
78       mlir::emitError(loc, "symbol \"")
79           << toStringRef(sym.name()) << "\" must already be in map";
80     return;
81   } else if (isResult) {
82     // Some Fortran results may be passed by argument (e.g. derived
83     // types)
84     if (symMap.lookupSymbol(sym))
85       return;
86   }
87   // Otherwise, it's a local variable or function result.
88   mlir::Value local = createNewLocal(converter, loc, var, {});
89   symMap.addSymbol(sym, local);
90 }
91 
92 void Fortran::lower::instantiateVariable(AbstractConverter &converter,
93                                          const pft::Variable &var,
94                                          SymMap &symMap) {
95   const Fortran::semantics::Symbol &sym = var.getSymbol();
96   const mlir::Location loc = converter.genLocation(sym.name());
97   if (var.isAggregateStore()) {
98     TODO(loc, "instantiateVariable AggregateStore");
99   } else if (Fortran::semantics::FindCommonBlockContaining(
100                  var.getSymbol().GetUltimate())) {
101     TODO(loc, "instantiateVariable Common");
102   } else if (var.isAlias()) {
103     TODO(loc, "instantiateVariable Alias");
104   } else if (var.isGlobal()) {
105     TODO(loc, "instantiateVariable Global");
106   } else {
107     instantiateLocal(converter, var, symMap);
108   }
109 }
110 
111 void Fortran::lower::mapCallInterfaceSymbols(
112     AbstractConverter &converter, const Fortran::lower::CallerInterface &caller,
113     SymMap &symMap) {
114   const Fortran::semantics::Symbol &result = caller.getResultSymbol();
115   for (Fortran::lower::pft::Variable var :
116        Fortran::lower::pft::buildFuncResultDependencyList(result)) {
117     if (var.isAggregateStore()) {
118       instantiateVariable(converter, var, symMap);
119     } else {
120       const Fortran::semantics::Symbol &sym = var.getSymbol();
121       const auto *hostDetails =
122           sym.detailsIf<Fortran::semantics::HostAssocDetails>();
123       if (hostDetails && !var.isModuleVariable()) {
124         // The callee is an internal procedure `A` whose result properties
125         // depend on host variables. The caller may be the host, or another
126         // internal procedure `B` contained in the same host.  In the first
127         // case, the host symbol is obviously mapped, in the second case, it
128         // must also be mapped because
129         // HostAssociations::internalProcedureBindings that was called when
130         // lowering `B` will have mapped all host symbols of captured variables
131         // to the tuple argument containing the composite of all host associated
132         // variables, whether or not the host symbol is actually referred to in
133         // `B`. Hence it is possible to simply lookup the variable associated to
134         // the host symbol without having to go back to the tuple argument.
135         Fortran::lower::SymbolBox hostValue =
136             symMap.lookupSymbol(hostDetails->symbol());
137         assert(hostValue && "callee host symbol must be mapped on caller side");
138         symMap.addSymbol(sym, hostValue.toExtendedValue());
139         // The SymbolBox associated to the host symbols is complete, skip
140         // instantiateVariable that would try to allocate a new storage.
141         continue;
142       }
143       if (Fortran::semantics::IsDummy(sym) && sym.owner() == result.owner()) {
144         // Get the argument for the dummy argument symbols of the current call.
145         symMap.addSymbol(sym, caller.getArgumentValue(sym));
146         // All the properties of the dummy variable may not come from the actual
147         // argument, let instantiateVariable handle this.
148       }
149       // If this is neither a host associated or dummy symbol, it must be a
150       // module or common block variable to satisfy specification expression
151       // requirements in 10.1.11, instantiateVariable will get its address and
152       // properties.
153       instantiateVariable(converter, var, symMap);
154     }
155   }
156 }
157