[clang] Improve the lifetime_capture_by diagnostic on the constructor. (#117792)
[llvm-project.git] / flang / lib / Optimizer / Support / InternalNames.cpp
blob011021c9f0350f53ef1e5edf62164564a771911f
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/
11 //===----------------------------------------------------------------------===//
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>
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)"));
26 constexpr std::int64_t badValue = -1;
28 inline std::string prefix() { return "_Q"; }
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(tag).append(mod.lower());
39 tag = "S";
41 for (auto proc : procs)
42 prefix.append("F").append(proc.lower());
43 if (blockId)
44 prefix.append("B").append(std::to_string(blockId));
45 return prefix;
48 inline llvm::SmallVector<llvm::StringRef>
49 convertToStringRef(llvm::ArrayRef<std::string> from) {
50 return {from.begin(), from.end()};
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;
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
70 return uniq.substr(init, i - init).str();
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
78 std::int64_t result = badValue;
79 if (uniq.substr(init, i - init).getAsInteger(10, result))
80 return badValue;
81 return result;
84 std::string fir::NameUniquer::toLower(llvm::StringRef name) {
85 return name.lower();
88 std::string fir::NameUniquer::intAsString(std::int64_t i) {
89 assert(i >= 0);
90 return std::to_string(i);
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));
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;
107 std::string fir::NameUniquer::doCommonBlock(llvm::StringRef name) {
108 return prefix().append("C").append(toLower(name));
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));
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));
133 std::string fir::NameUniquer::doGenerated(llvm::StringRef name) {
134 return prefix().append("Q").append(name);
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);
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;
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));
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));
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));
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));
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);
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));
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));
240 llvm::StringRef fir::NameUniquer::doProgramEntry() {
241 if (mainEntryName.size())
242 return mainEntryName;
243 return "_QQmain";
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);
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);
317 break;
318 default:
319 assert(false && "unknown uniquing code");
320 break;
323 return {nk, DeconstructedName(modules, procs, blockId, name, kinds)};
325 return {NameKind::NOT_UNIQUED, DeconstructedName(uniq)};
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();
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);
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;
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;
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);
379 std::string
380 fir::NameUniquer::getTypeDescriptorName(llvm::StringRef mangledTypeName) {
381 return getDerivedTypeObjectName(mangledTypeName,
382 fir::kTypeDescriptorSeparator);
385 std::string fir::NameUniquer::getTypeDescriptorAssemblyName(
386 llvm::StringRef mangledTypeName) {
387 return replaceSpecialSymbols(getTypeDescriptorName(mangledTypeName));
390 std::string fir::NameUniquer::getTypeDescriptorBindingTableName(
391 llvm::StringRef mangledTypeName) {
392 return getDerivedTypeObjectName(mangledTypeName, fir::kBindingTableSeparator);
395 std::string
396 fir::NameUniquer::getComponentInitName(llvm::StringRef mangledTypeName,
397 llvm::StringRef componentName) {
399 std::string prefix =
400 getDerivedTypeObjectName(mangledTypeName, fir::kComponentInitSeparator);
401 return (prefix + fir::kNameSeparator + componentName).str();
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;
411 std::string fir::NameUniquer::replaceSpecialSymbols(const std::string &name) {
412 return std::regex_replace(name, std::regex{"\\."}, "X");
415 bool fir::NameUniquer::isSpecialSymbol(llvm::StringRef name) {
416 return !name.empty() && (name[0] == '.' || name[0] == 'X');