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

source code of flang/lib/Optimizer/Support/InternalNames.cpp