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