1 | //===-- Mangler.cpp -------------------------------------------------------===// |
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/Mangler.h" |
10 | #include "flang/Common/reference.h" |
11 | #include "flang/Lower/Support/Utils.h" |
12 | #include "flang/Optimizer/Builder/Todo.h" |
13 | #include "flang/Optimizer/Dialect/FIRType.h" |
14 | #include "flang/Optimizer/Support/InternalNames.h" |
15 | #include "flang/Semantics/tools.h" |
16 | #include "llvm/ADT/ArrayRef.h" |
17 | #include "llvm/ADT/SmallVector.h" |
18 | #include "llvm/ADT/StringRef.h" |
19 | #include "llvm/Support/MD5.h" |
20 | |
21 | /// Return all ancestor module and submodule scope names; all host procedure |
22 | /// and statement function scope names; and the innermost blockId containing |
23 | /// \p scope, including scope itself. |
24 | static std::tuple<llvm::SmallVector<llvm::StringRef>, |
25 | llvm::SmallVector<llvm::StringRef>, std::int64_t> |
26 | ancestors(const Fortran::semantics::Scope &scope, |
27 | Fortran::lower::mangle::ScopeBlockIdMap &scopeBlockIdMap) { |
28 | llvm::SmallVector<const Fortran::semantics::Scope *> scopes; |
29 | for (auto *scp = &scope; !scp->IsGlobal(); scp = &scp->parent()) |
30 | scopes.push_back(scp); |
31 | llvm::SmallVector<llvm::StringRef> modules; |
32 | llvm::SmallVector<llvm::StringRef> procs; |
33 | std::int64_t blockId = 0; |
34 | for (auto iter = scopes.rbegin(), rend = scopes.rend(); iter != rend; |
35 | ++iter) { |
36 | auto *scp = *iter; |
37 | switch (scp->kind()) { |
38 | case Fortran::semantics::Scope::Kind::Module: |
39 | modules.emplace_back(toStringRef(scp->symbol()->name())); |
40 | break; |
41 | case Fortran::semantics::Scope::Kind::Subprogram: |
42 | procs.emplace_back(toStringRef(scp->symbol()->name())); |
43 | break; |
44 | case Fortran::semantics::Scope::Kind::MainProgram: |
45 | // Do not use the main program name, if any, because it may collide |
46 | // with a procedure of the same name in another compilation unit. |
47 | // This is nonconformant, but universally allowed. |
48 | procs.emplace_back(Args: llvm::StringRef("" )); |
49 | break; |
50 | case Fortran::semantics::Scope::Kind::BlockConstruct: { |
51 | auto it = scopeBlockIdMap.find(scp); |
52 | assert(it != scopeBlockIdMap.end() && it->second && |
53 | "invalid block identifier" ); |
54 | blockId = it->second; |
55 | } break; |
56 | default: |
57 | break; |
58 | } |
59 | } |
60 | return {modules, procs, blockId}; |
61 | } |
62 | |
63 | /// Return all ancestor module and submodule scope names; all host procedure |
64 | /// and statement function scope names; and the innermost blockId containing |
65 | /// \p symbol. |
66 | static std::tuple<llvm::SmallVector<llvm::StringRef>, |
67 | llvm::SmallVector<llvm::StringRef>, std::int64_t> |
68 | ancestors(const Fortran::semantics::Symbol &symbol, |
69 | Fortran::lower::mangle::ScopeBlockIdMap &scopeBlockIdMap) { |
70 | return ancestors(symbol.owner(), scopeBlockIdMap); |
71 | } |
72 | |
73 | /// Return a globally unique string for a compiler generated \p name. |
74 | std::string |
75 | Fortran::lower::mangle::mangleName(std::string &name, |
76 | const Fortran::semantics::Scope &scope, |
77 | ScopeBlockIdMap &scopeBlockIdMap) { |
78 | llvm::SmallVector<llvm::StringRef> modules; |
79 | llvm::SmallVector<llvm::StringRef> procs; |
80 | std::int64_t blockId; |
81 | std::tie(modules, procs, blockId) = ancestors(scope, scopeBlockIdMap); |
82 | return fir::NameUniquer::doGenerated(modules, procs, blockId, name); |
83 | } |
84 | |
85 | // Mangle the name of \p symbol to make it globally unique. |
86 | std::string Fortran::lower::mangle::mangleName( |
87 | const Fortran::semantics::Symbol &symbol, ScopeBlockIdMap &scopeBlockIdMap, |
88 | bool keepExternalInScope, bool underscoring) { |
89 | // Resolve module and host associations before mangling. |
90 | const auto &ultimateSymbol = symbol.GetUltimate(); |
91 | |
92 | // The Fortran and BIND(C) namespaces are counterintuitive. A BIND(C) name is |
93 | // substituted early, and has precedence over the Fortran name. This allows |
94 | // multiple procedures or objects with identical Fortran names to legally |
95 | // coexist. The BIND(C) name is unique. |
96 | if (auto *overrideName = ultimateSymbol.GetBindName()) |
97 | return *overrideName; |
98 | |
99 | llvm::StringRef symbolName = toStringRef(ultimateSymbol.name()); |
100 | llvm::SmallVector<llvm::StringRef> modules; |
101 | llvm::SmallVector<llvm::StringRef> procs; |
102 | std::int64_t blockId; |
103 | |
104 | // mangle ObjectEntityDetails or AssocEntityDetails symbols. |
105 | auto mangleObject = [&]() -> std::string { |
106 | std::tie(modules, procs, blockId) = |
107 | ancestors(ultimateSymbol, scopeBlockIdMap); |
108 | if (Fortran::semantics::IsNamedConstant(ultimateSymbol)) |
109 | return fir::NameUniquer::doConstant(modules, procs, blockId, symbolName); |
110 | return fir::NameUniquer::doVariable(modules, procs, blockId, symbolName); |
111 | }; |
112 | |
113 | return std::visit( |
114 | Fortran::common::visitors{ |
115 | [&](const Fortran::semantics::MainProgramDetails &) { |
116 | return fir::NameUniquer::doProgramEntry().str(); |
117 | }, |
118 | [&](const Fortran::semantics::SubprogramDetails &subpDetails) { |
119 | // Mangle external procedure without any scope prefix. |
120 | if (!keepExternalInScope && |
121 | Fortran::semantics::IsExternal(ultimateSymbol)) |
122 | return fir::NameUniquer::doProcedure(std::nullopt, std::nullopt, |
123 | symbolName); |
124 | // A separate module procedure must be mangled according to its |
125 | // declaration scope, not its definition scope. |
126 | const Fortran::semantics::Symbol *interface = &ultimateSymbol; |
127 | if (interface->attrs().test(Fortran::semantics::Attr::MODULE) && |
128 | interface->owner().IsSubmodule() && !subpDetails.isInterface()) |
129 | interface = subpDetails.moduleInterface(); |
130 | std::tie(modules, procs, blockId) = ancestors( |
131 | interface ? *interface : ultimateSymbol, scopeBlockIdMap); |
132 | return fir::NameUniquer::doProcedure(modules, procs, symbolName); |
133 | }, |
134 | [&](const Fortran::semantics::ProcEntityDetails &) { |
135 | // Mangle procedure pointers and dummy procedures as variables. |
136 | if (Fortran::semantics::IsPointer(ultimateSymbol) || |
137 | Fortran::semantics::IsDummy(ultimateSymbol)) { |
138 | std::tie(modules, procs, blockId) = |
139 | ancestors(ultimateSymbol, scopeBlockIdMap); |
140 | return fir::NameUniquer::doVariable(modules, procs, blockId, |
141 | symbolName); |
142 | } |
143 | // Otherwise, this is an external procedure, with or without an |
144 | // explicit EXTERNAL attribute. Mangle it without any prefix. |
145 | return fir::NameUniquer::doProcedure(std::nullopt, std::nullopt, |
146 | symbolName); |
147 | }, |
148 | [&](const Fortran::semantics::ObjectEntityDetails &) { |
149 | return mangleObject(); |
150 | }, |
151 | [&](const Fortran::semantics::AssocEntityDetails &) { |
152 | return mangleObject(); |
153 | }, |
154 | [&](const Fortran::semantics::NamelistDetails &) { |
155 | std::tie(modules, procs, blockId) = |
156 | ancestors(ultimateSymbol, scopeBlockIdMap); |
157 | return fir::NameUniquer::doNamelistGroup(modules, procs, |
158 | symbolName); |
159 | }, |
160 | [&](const Fortran::semantics::CommonBlockDetails &) { |
161 | return Fortran::semantics::GetCommonBlockObjectName(ultimateSymbol, |
162 | underscoring); |
163 | }, |
164 | [&](const Fortran::semantics::ProcBindingDetails &procBinding) { |
165 | return mangleName(procBinding.symbol(), scopeBlockIdMap, |
166 | keepExternalInScope, underscoring); |
167 | }, |
168 | [&](const Fortran::semantics::DerivedTypeDetails &) -> std::string { |
169 | // Derived type mangling must use mangleName(DerivedTypeSpec) so |
170 | // that kind type parameter values can be mangled. |
171 | llvm::report_fatal_error( |
172 | "only derived type instances can be mangled" ); |
173 | }, |
174 | [](const auto &) -> std::string { TODO_NOLOC("symbol mangling" ); }, |
175 | }, |
176 | ultimateSymbol.details()); |
177 | } |
178 | |
179 | std::string |
180 | Fortran::lower::mangle::mangleName(const Fortran::semantics::Symbol &symbol, |
181 | bool keepExternalInScope, |
182 | bool underscoring) { |
183 | assert((symbol.owner().kind() != |
184 | Fortran::semantics::Scope::Kind::BlockConstruct || |
185 | symbol.has<Fortran::semantics::SubprogramDetails>() || |
186 | Fortran::semantics::IsBindCProcedure(symbol)) && |
187 | "block object mangling must specify a scopeBlockIdMap" ); |
188 | ScopeBlockIdMap scopeBlockIdMap; |
189 | return mangleName(symbol, scopeBlockIdMap, keepExternalInScope, underscoring); |
190 | } |
191 | |
192 | std::string Fortran::lower::mangle::mangleName( |
193 | const Fortran::semantics::DerivedTypeSpec &derivedType, |
194 | ScopeBlockIdMap &scopeBlockIdMap) { |
195 | // Resolve module and host associations before mangling. |
196 | const Fortran::semantics::Symbol &ultimateSymbol = |
197 | derivedType.typeSymbol().GetUltimate(); |
198 | |
199 | llvm::StringRef symbolName = toStringRef(ultimateSymbol.name()); |
200 | llvm::SmallVector<llvm::StringRef> modules; |
201 | llvm::SmallVector<llvm::StringRef> procs; |
202 | std::int64_t blockId; |
203 | std::tie(modules, procs, blockId) = |
204 | ancestors(ultimateSymbol, scopeBlockIdMap); |
205 | llvm::SmallVector<std::int64_t> kinds; |
206 | for (const auto ¶m : |
207 | Fortran::semantics::OrderParameterDeclarations(ultimateSymbol)) { |
208 | const auto ¶mDetails = |
209 | param->get<Fortran::semantics::TypeParamDetails>(); |
210 | if (paramDetails.attr() == Fortran::common::TypeParamAttr::Kind) { |
211 | const Fortran::semantics::ParamValue *paramValue = |
212 | derivedType.FindParameter(param->name()); |
213 | assert(paramValue && "derived type kind parameter value not found" ); |
214 | const Fortran::semantics::MaybeIntExpr paramExpr = |
215 | paramValue->GetExplicit(); |
216 | assert(paramExpr && "derived type kind param not explicit" ); |
217 | std::optional<int64_t> init = |
218 | Fortran::evaluate::ToInt64(paramValue->GetExplicit()); |
219 | assert(init && "derived type kind param is not constant" ); |
220 | kinds.emplace_back(*init); |
221 | } |
222 | } |
223 | return fir::NameUniquer::doType(modules, procs, blockId, symbolName, kinds); |
224 | } |
225 | |
226 | std::string Fortran::lower::mangle::getRecordTypeFieldName( |
227 | const Fortran::semantics::Symbol &component, |
228 | ScopeBlockIdMap &scopeBlockIdMap) { |
229 | if (!component.attrs().test(Fortran::semantics::Attr::PRIVATE)) |
230 | return component.name().ToString(); |
231 | const Fortran::semantics::DerivedTypeSpec *componentParentType = |
232 | component.owner().derivedTypeSpec(); |
233 | assert(componentParentType && |
234 | "failed to retrieve private component parent type" ); |
235 | // Do not mangle Iso C C_PTR and C_FUNPTR components. This type cannot be |
236 | // extended as per Fortran 2018 7.5.7.1, mangling them makes the IR unreadable |
237 | // when using ISO C modules, and lowering needs to know the component way |
238 | // without access to semantics::Symbol. |
239 | if (Fortran::semantics::IsIsoCType(componentParentType)) |
240 | return component.name().ToString(); |
241 | return mangleName(*componentParentType, scopeBlockIdMap) + "." + |
242 | component.name().ToString(); |
243 | } |
244 | |
245 | std::string Fortran::lower::mangle::demangleName(llvm::StringRef name) { |
246 | auto result = fir::NameUniquer::deconstruct(name); |
247 | return result.second.name; |
248 | } |
249 | |
250 | //===----------------------------------------------------------------------===// |
251 | // Array Literals Mangling |
252 | //===----------------------------------------------------------------------===// |
253 | |
254 | static std::string typeToString(Fortran::common::TypeCategory cat, int kind, |
255 | llvm::StringRef derivedName) { |
256 | switch (cat) { |
257 | case Fortran::common::TypeCategory::Integer: |
258 | return "i" + std::to_string(val: kind); |
259 | case Fortran::common::TypeCategory::Real: |
260 | return "r" + std::to_string(val: kind); |
261 | case Fortran::common::TypeCategory::Complex: |
262 | return "z" + std::to_string(val: kind); |
263 | case Fortran::common::TypeCategory::Logical: |
264 | return "l" + std::to_string(val: kind); |
265 | case Fortran::common::TypeCategory::Character: |
266 | return "c" + std::to_string(val: kind); |
267 | case Fortran::common::TypeCategory::Derived: |
268 | return derivedName.str(); |
269 | } |
270 | llvm_unreachable("bad TypeCategory" ); |
271 | } |
272 | |
273 | std::string Fortran::lower::mangle::mangleArrayLiteral( |
274 | size_t size, const Fortran::evaluate::ConstantSubscripts &shape, |
275 | Fortran::common::TypeCategory cat, int kind, |
276 | Fortran::common::ConstantSubscript charLen, llvm::StringRef derivedName) { |
277 | std::string typeId; |
278 | for (Fortran::evaluate::ConstantSubscript extent : shape) |
279 | typeId.append(std::to_string(extent)).append("x" ); |
280 | if (charLen >= 0) |
281 | typeId.append(std::to_string(charLen)).append("x" ); |
282 | typeId.append(typeToString(cat, kind, derivedName)); |
283 | std::string name = |
284 | fir::NameUniquer::doGenerated("ro."s .append(typeId).append("." )); |
285 | if (!size) |
286 | name += "null." ; |
287 | return name; |
288 | } |
289 | |
290 | std::string Fortran::lower::mangle::globalNamelistDescriptorName( |
291 | const Fortran::semantics::Symbol &sym) { |
292 | std::string name = mangleName(sym); |
293 | return IsAllocatableOrObjectPointer(&sym) ? name : name + ".desc"s ; |
294 | } |
295 | |