1 | //===-- InternalNames.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 | // Coding style: https://mlir.llvm.org/getting_started/DeveloperGuide/ |
10 | // |
11 | //===----------------------------------------------------------------------===// |
12 | |
13 | #include "flang/Optimizer/Support/InternalNames.h" |
14 | #include "flang/Optimizer/Dialect/FIRType.h" |
15 | #include "mlir/IR/BuiltinTypes.h" |
16 | #include "mlir/IR/Diagnostics.h" |
17 | #include "llvm/Support/CommandLine.h" |
18 | #include <optional> |
19 | #include <regex> |
20 | |
21 | static llvm::cl::opt<std::string> mainEntryName( |
22 | "main-entry-name" , |
23 | llvm::cl::desc("override the name of the default PROGRAM entry (may be " |
24 | "helpful for using other runtimes)" )); |
25 | |
26 | constexpr std::int64_t badValue = -1; |
27 | |
28 | inline std::string prefix() { return "_Q" ; } |
29 | |
30 | /// Generate a mangling prefix from module, submodule, procedure, and |
31 | /// statement function names, plus an (innermost) block scope id. |
32 | static std::string doAncestors(llvm::ArrayRef<llvm::StringRef> modules, |
33 | llvm::ArrayRef<llvm::StringRef> procs, |
34 | std::int64_t blockId = 0) { |
35 | std::string prefix; |
36 | const char *tag = "M" ; |
37 | for (auto mod : modules) { |
38 | prefix.append(s: tag).append(str: mod.lower()); |
39 | tag = "S" ; |
40 | } |
41 | for (auto proc : procs) |
42 | prefix.append(s: "F" ).append(str: proc.lower()); |
43 | if (blockId) |
44 | prefix.append(s: "B" ).append(str: std::to_string(val: blockId)); |
45 | return prefix; |
46 | } |
47 | |
48 | inline llvm::SmallVector<llvm::StringRef> |
49 | convertToStringRef(llvm::ArrayRef<std::string> from) { |
50 | return {from.begin(), from.end()}; |
51 | } |
52 | |
53 | inline std::optional<llvm::StringRef> |
54 | convertToStringRef(const std::optional<std::string> &from) { |
55 | std::optional<llvm::StringRef> to; |
56 | if (from) |
57 | to = *from; |
58 | return to; |
59 | } |
60 | |
61 | static std::string readName(llvm::StringRef uniq, std::size_t &i, |
62 | std::size_t init, std::size_t end) { |
63 | // Allow 'X' to be part of the mangled name, which |
64 | // can happen after the special symbols are replaced |
65 | // in the mangled names by CompilerGeneratedNamesConversionPass. |
66 | for (i = init; i < end && (uniq[i] < 'A' || uniq[i] > 'Z' || uniq[i] == 'X'); |
67 | ++i) { |
68 | // do nothing |
69 | } |
70 | return uniq.substr(Start: init, N: i - init).str(); |
71 | } |
72 | |
73 | static std::int64_t readInt(llvm::StringRef uniq, std::size_t &i, |
74 | std::size_t init, std::size_t end) { |
75 | for (i = init; i < end && uniq[i] >= '0' && uniq[i] <= '9'; ++i) { |
76 | // do nothing |
77 | } |
78 | std::int64_t result = badValue; |
79 | if (uniq.substr(Start: init, N: i - init).getAsInteger(Radix: 10, Result&: result)) |
80 | return badValue; |
81 | return result; |
82 | } |
83 | |
84 | std::string fir::NameUniquer::toLower(llvm::StringRef name) { |
85 | return name.lower(); |
86 | } |
87 | |
88 | std::string fir::NameUniquer::intAsString(std::int64_t i) { |
89 | assert(i >= 0); |
90 | return std::to_string(i); |
91 | } |
92 | |
93 | std::string fir::NameUniquer::doKind(std::int64_t kind) { |
94 | std::string result = "K" ; |
95 | if (kind < 0) |
96 | return result.append("N" ).append(intAsString(-kind)); |
97 | return result.append(intAsString(kind)); |
98 | } |
99 | |
100 | std::string fir::NameUniquer::doKinds(llvm::ArrayRef<std::int64_t> kinds) { |
101 | std::string result; |
102 | for (auto i : kinds) |
103 | result.append(doKind(i)); |
104 | return result; |
105 | } |
106 | |
107 | std::string fir::NameUniquer::doCommonBlock(llvm::StringRef name) { |
108 | return prefix().append("C" ).append(toLower(name)); |
109 | } |
110 | |
111 | std::string |
112 | fir::NameUniquer::doConstant(llvm::ArrayRef<llvm::StringRef> modules, |
113 | llvm::ArrayRef<llvm::StringRef> procs, |
114 | std::int64_t blockId, llvm::StringRef name) { |
115 | return prefix() |
116 | .append(doAncestors(modules, procs, blockId)) |
117 | .append("EC" ) |
118 | .append(toLower(name)); |
119 | } |
120 | |
121 | std::string |
122 | fir::NameUniquer::doDispatchTable(llvm::ArrayRef<llvm::StringRef> modules, |
123 | llvm::ArrayRef<llvm::StringRef> procs, |
124 | std::int64_t blockId, llvm::StringRef name, |
125 | llvm::ArrayRef<std::int64_t> kinds) { |
126 | return prefix() |
127 | .append(doAncestors(modules, procs, blockId)) |
128 | .append("DT" ) |
129 | .append(toLower(name)) |
130 | .append(doKinds(kinds)); |
131 | } |
132 | |
133 | std::string fir::NameUniquer::doGenerated(llvm::StringRef name) { |
134 | return prefix().append("Q" ).append(name); |
135 | } |
136 | |
137 | std::string |
138 | fir::NameUniquer::doGenerated(llvm::ArrayRef<llvm::StringRef> modules, |
139 | llvm::ArrayRef<llvm::StringRef> procs, |
140 | std::int64_t blockId, llvm::StringRef name) { |
141 | return prefix() |
142 | .append("Q" ) |
143 | .append(doAncestors(modules, procs, blockId)) |
144 | .append(name); |
145 | } |
146 | |
147 | std::string fir::NameUniquer::doIntrinsicTypeDescriptor( |
148 | llvm::ArrayRef<llvm::StringRef> modules, |
149 | llvm::ArrayRef<llvm::StringRef> procs, std::int64_t blockId, |
150 | IntrinsicType type, std::int64_t kind) { |
151 | const char *name = nullptr; |
152 | switch (type) { |
153 | case IntrinsicType::CHARACTER: |
154 | name = "character" ; |
155 | break; |
156 | case IntrinsicType::COMPLEX: |
157 | name = "complex" ; |
158 | break; |
159 | case IntrinsicType::INTEGER: |
160 | name = "integer" ; |
161 | break; |
162 | case IntrinsicType::LOGICAL: |
163 | name = "logical" ; |
164 | break; |
165 | case IntrinsicType::REAL: |
166 | name = "real" ; |
167 | break; |
168 | } |
169 | assert(name && "unknown intrinsic type" ); |
170 | return prefix() |
171 | .append(doAncestors(modules, procs, blockId)) |
172 | .append("YI" ) |
173 | .append(name) |
174 | .append(doKind(kind)); |
175 | } |
176 | |
177 | std::string |
178 | fir::NameUniquer::doProcedure(llvm::ArrayRef<llvm::StringRef> modules, |
179 | llvm::ArrayRef<llvm::StringRef> procs, |
180 | llvm::StringRef name) { |
181 | return prefix() |
182 | .append(doAncestors(modules, procs)) |
183 | .append("P" ) |
184 | .append(toLower(name)); |
185 | } |
186 | |
187 | std::string fir::NameUniquer::doType(llvm::ArrayRef<llvm::StringRef> modules, |
188 | llvm::ArrayRef<llvm::StringRef> procs, |
189 | std::int64_t blockId, llvm::StringRef name, |
190 | llvm::ArrayRef<std::int64_t> kinds) { |
191 | return prefix() |
192 | .append(doAncestors(modules, procs, blockId)) |
193 | .append("T" ) |
194 | .append(toLower(name)) |
195 | .append(doKinds(kinds)); |
196 | } |
197 | |
198 | std::string |
199 | fir::NameUniquer::doTypeDescriptor(llvm::ArrayRef<llvm::StringRef> modules, |
200 | llvm::ArrayRef<llvm::StringRef> procs, |
201 | std::int64_t blockId, llvm::StringRef name, |
202 | llvm::ArrayRef<std::int64_t> kinds) { |
203 | return prefix() |
204 | .append(doAncestors(modules, procs, blockId)) |
205 | .append("CT" ) |
206 | .append(toLower(name)) |
207 | .append(doKinds(kinds)); |
208 | } |
209 | |
210 | std::string |
211 | fir::NameUniquer::doTypeDescriptor(llvm::ArrayRef<std::string> modules, |
212 | llvm::ArrayRef<std::string> procs, |
213 | std::int64_t blockId, llvm::StringRef name, |
214 | llvm::ArrayRef<std::int64_t> kinds) { |
215 | auto rmodules = convertToStringRef(modules); |
216 | auto rprocs = convertToStringRef(procs); |
217 | return doTypeDescriptor(rmodules, rprocs, blockId, name, kinds); |
218 | } |
219 | |
220 | std::string |
221 | fir::NameUniquer::doVariable(llvm::ArrayRef<llvm::StringRef> modules, |
222 | llvm::ArrayRef<llvm::StringRef> procs, |
223 | std::int64_t blockId, llvm::StringRef name) { |
224 | return prefix() |
225 | .append(doAncestors(modules, procs, blockId)) |
226 | .append("E" ) |
227 | .append(toLower(name)); |
228 | } |
229 | |
230 | std::string |
231 | fir::NameUniquer::doNamelistGroup(llvm::ArrayRef<llvm::StringRef> modules, |
232 | llvm::ArrayRef<llvm::StringRef> procs, |
233 | llvm::StringRef name) { |
234 | return prefix() |
235 | .append(doAncestors(modules, procs)) |
236 | .append("N" ) |
237 | .append(toLower(name)); |
238 | } |
239 | |
240 | llvm::StringRef fir::NameUniquer::doProgramEntry() { |
241 | if (mainEntryName.size()) |
242 | return mainEntryName; |
243 | return "_QQmain" ; |
244 | } |
245 | |
246 | std::pair<fir::NameUniquer::NameKind, fir::NameUniquer::DeconstructedName> |
247 | fir::NameUniquer::deconstruct(llvm::StringRef uniq) { |
248 | uniq = fir::NameUniquer::dropTypeConversionMarkers(uniq); |
249 | if (uniq.starts_with("_Q" )) { |
250 | llvm::SmallVector<std::string> modules; |
251 | llvm::SmallVector<std::string> procs; |
252 | std::int64_t blockId = 0; |
253 | std::string name; |
254 | llvm::SmallVector<std::int64_t> kinds; |
255 | NameKind nk = NameKind::NOT_UNIQUED; |
256 | for (std::size_t i = 2, end{uniq.size()}; i != end;) { |
257 | switch (uniq[i]) { |
258 | case 'B': // Block |
259 | blockId = readInt(uniq, i, i + 1, end); |
260 | break; |
261 | case 'C': // Common block |
262 | nk = NameKind::COMMON; |
263 | name = readName(uniq, i, i + 1, end); |
264 | break; |
265 | case 'D': // Dispatch table |
266 | nk = NameKind::DISPATCH_TABLE; |
267 | assert(uniq[i + 1] == 'T'); |
268 | name = readName(uniq, i, i + 2, end); |
269 | break; |
270 | case 'E': |
271 | if (uniq[i + 1] == 'C') { // Constant Entity |
272 | nk = NameKind::CONSTANT; |
273 | name = readName(uniq, i, i + 2, end); |
274 | } else { // variable Entity |
275 | nk = NameKind::VARIABLE; |
276 | name = readName(uniq, i, i + 1, end); |
277 | } |
278 | break; |
279 | case 'F': // procedure/Function ancestor component of a mangled prefix |
280 | procs.push_back(readName(uniq, i, i + 1, end)); |
281 | break; |
282 | case 'K': |
283 | if (uniq[i + 1] == 'N') // Negative Kind |
284 | kinds.push_back(-readInt(uniq, i, i + 2, end)); |
285 | else // [positive] Kind |
286 | kinds.push_back(readInt(uniq, i, i + 1, end)); |
287 | break; |
288 | case 'M': // Module |
289 | case 'S': // Submodule |
290 | modules.push_back(readName(uniq, i, i + 1, end)); |
291 | break; |
292 | case 'N': // Namelist group |
293 | nk = NameKind::NAMELIST_GROUP; |
294 | name = readName(uniq, i, i + 1, end); |
295 | break; |
296 | case 'P': // Procedure/function (itself) |
297 | nk = NameKind::PROCEDURE; |
298 | name = readName(uniq, i, i + 1, end); |
299 | break; |
300 | case 'Q': // UniQue mangle name tag |
301 | nk = NameKind::GENERATED; |
302 | name = uniq; |
303 | i = end; |
304 | break; |
305 | case 'T': // derived Type |
306 | nk = NameKind::DERIVED_TYPE; |
307 | name = readName(uniq, i, i + 1, end); |
308 | break; |
309 | case 'Y': |
310 | if (uniq[i + 1] == 'I') { // tYpe descriptor for an Intrinsic type |
311 | nk = NameKind::INTRINSIC_TYPE_DESC; |
312 | name = readName(uniq, i, i + 1, end); |
313 | } else { // tYpe descriptor |
314 | nk = NameKind::TYPE_DESC; |
315 | name = readName(uniq, i, i + 2, end); |
316 | } |
317 | break; |
318 | default: |
319 | assert(false && "unknown uniquing code" ); |
320 | break; |
321 | } |
322 | } |
323 | return {nk, DeconstructedName(modules, procs, blockId, name, kinds)}; |
324 | } |
325 | return {NameKind::NOT_UNIQUED, DeconstructedName(uniq)}; |
326 | } |
327 | |
328 | bool fir::NameUniquer::isExternalFacingUniquedName( |
329 | const std::pair<fir::NameUniquer::NameKind, |
330 | fir::NameUniquer::DeconstructedName> &deconstructResult) { |
331 | return (deconstructResult.first == NameKind::PROCEDURE || |
332 | deconstructResult.first == NameKind::COMMON) && |
333 | deconstructResult.second.modules.empty() && |
334 | deconstructResult.second.procs.empty(); |
335 | } |
336 | |
337 | bool fir::NameUniquer::needExternalNameMangling(llvm::StringRef uniquedName) { |
338 | auto result = fir::NameUniquer::deconstruct(uniquedName); |
339 | return result.first != fir::NameUniquer::NameKind::NOT_UNIQUED && |
340 | fir::NameUniquer::isExternalFacingUniquedName(result); |
341 | } |
342 | |
343 | bool fir::NameUniquer::belongsToModule(llvm::StringRef uniquedName, |
344 | llvm::StringRef moduleName) { |
345 | auto result = fir::NameUniquer::deconstruct(uniquedName); |
346 | return !result.second.modules.empty() && |
347 | result.second.modules[0] == moduleName; |
348 | } |
349 | |
350 | static std::string |
351 | mangleTypeDescriptorKinds(llvm::ArrayRef<std::int64_t> kinds) { |
352 | if (kinds.empty()) |
353 | return "" ; |
354 | std::string result; |
355 | for (std::int64_t kind : kinds) |
356 | result += (fir::kNameSeparator + std::to_string(kind)).str(); |
357 | return result; |
358 | } |
359 | |
360 | static std::string getDerivedTypeObjectName(llvm::StringRef mangledTypeName, |
361 | const llvm::StringRef separator) { |
362 | mangledTypeName = |
363 | fir::NameUniquer::dropTypeConversionMarkers(mangledTypeName); |
364 | auto result = fir::NameUniquer::deconstruct(mangledTypeName); |
365 | if (result.first != fir::NameUniquer::NameKind::DERIVED_TYPE) |
366 | return "" ; |
367 | std::string varName = separator.str() + result.second.name + |
368 | mangleTypeDescriptorKinds(result.second.kinds); |
369 | llvm::SmallVector<llvm::StringRef> modules; |
370 | for (const std::string &mod : result.second.modules) |
371 | modules.push_back(mod); |
372 | llvm::SmallVector<llvm::StringRef> procs; |
373 | for (const std::string &proc : result.second.procs) |
374 | procs.push_back(proc); |
375 | return fir::NameUniquer::doVariable(modules, procs, result.second.blockId, |
376 | varName); |
377 | } |
378 | |
379 | std::string |
380 | fir::NameUniquer::getTypeDescriptorName(llvm::StringRef mangledTypeName) { |
381 | return getDerivedTypeObjectName(mangledTypeName, |
382 | fir::kTypeDescriptorSeparator); |
383 | } |
384 | |
385 | std::string fir::NameUniquer::getTypeDescriptorAssemblyName( |
386 | llvm::StringRef mangledTypeName) { |
387 | return replaceSpecialSymbols(getTypeDescriptorName(mangledTypeName)); |
388 | } |
389 | |
390 | std::string fir::NameUniquer::getTypeDescriptorBindingTableName( |
391 | llvm::StringRef mangledTypeName) { |
392 | return getDerivedTypeObjectName(mangledTypeName, fir::kBindingTableSeparator); |
393 | } |
394 | |
395 | std::string |
396 | fir::NameUniquer::getComponentInitName(llvm::StringRef mangledTypeName, |
397 | llvm::StringRef componentName) { |
398 | |
399 | std::string prefix = |
400 | getDerivedTypeObjectName(mangledTypeName, fir::kComponentInitSeparator); |
401 | return (prefix + fir::kNameSeparator + componentName).str(); |
402 | } |
403 | |
404 | llvm::StringRef |
405 | fir::NameUniquer::dropTypeConversionMarkers(llvm::StringRef mangledTypeName) { |
406 | if (mangledTypeName.ends_with(fir::boxprocSuffix)) |
407 | return mangledTypeName.drop_back(fir::boxprocSuffix.size()); |
408 | return mangledTypeName; |
409 | } |
410 | |
411 | std::string fir::NameUniquer::replaceSpecialSymbols(const std::string &name) { |
412 | return std::regex_replace(name, std::regex{"\\." }, "X" ); |
413 | } |
414 | |
415 | bool fir::NameUniquer::isSpecialSymbol(llvm::StringRef name) { |
416 | return !name.empty() && (name[0] == '.' || name[0] == 'X'); |
417 | } |
418 | |