xref: /llvm-project/flang/lib/Optimizer/Support/InternalNames.cpp (revision 6a66b8224d8cbdb6156b9a12d9339fee71898941)
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 
20 static 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 
25 constexpr std::int64_t badValue = -1;
26 
27 inline 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.
31 static 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(tag).append(mod.lower());
38     tag = "S";
39   }
40   for (auto proc : procs)
41     prefix.append("F").append(proc.lower());
42   if (blockId)
43     prefix.append("B").append(std::to_string(blockId));
44   return prefix;
45 }
46 
47 inline llvm::SmallVector<llvm::StringRef>
48 convertToStringRef(llvm::ArrayRef<std::string> from) {
49   return {from.begin(), from.end()};
50 }
51 
52 inline std::optional<llvm::StringRef>
53 convertToStringRef(const std::optional<std::string> &from) {
54   std::optional<llvm::StringRef> to;
55   if (from)
56     to = *from;
57   return to;
58 }
59 
60 static 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(init, i - init).str();
66 }
67 
68 static 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(init, i - init).getAsInteger(10, result))
75     return badValue;
76   return result;
77 }
78 
79 std::string fir::NameUniquer::toLower(llvm::StringRef name) {
80   return name.lower();
81 }
82 
83 std::string fir::NameUniquer::intAsString(std::int64_t i) {
84   assert(i >= 0);
85   return std::to_string(i);
86 }
87 
88 std::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 
95 std::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 
102 std::string fir::NameUniquer::doCommonBlock(llvm::StringRef name) {
103   return prefix().append("C").append(toLower(name));
104 }
105 
106 std::string
107 fir::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 
116 std::string
117 fir::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 
128 std::string fir::NameUniquer::doGenerated(llvm::StringRef name) {
129   return prefix().append("Q").append(name);
130 }
131 
132 std::string
133 fir::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 
142 std::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 
172 std::string
173 fir::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 
182 std::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 
193 std::string
194 fir::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 
205 std::string
206 fir::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 
215 std::string
216 fir::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 
225 std::string
226 fir::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 
235 llvm::StringRef fir::NameUniquer::doProgramEntry() {
236   if (mainEntryName.size())
237     return mainEntryName;
238   return "_QQmain";
239 }
240 
241 std::pair<fir::NameUniquer::NameKind, fir::NameUniquer::DeconstructedName>
242 fir::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 
323 bool 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 
332 bool 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 
338 bool 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 
345 static std::string
346 mangleTypeDescriptorKinds(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(kind);
352   return result;
353 }
354 
355 static 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 
374 std::string
375 fir::NameUniquer::getTypeDescriptorName(llvm::StringRef mangledTypeName) {
376   return getDerivedTypeObjectName(mangledTypeName, typeDescriptorSeparator);
377 }
378 
379 std::string fir::NameUniquer::getTypeDescriptorBindingTableName(
380     llvm::StringRef mangledTypeName) {
381   return getDerivedTypeObjectName(mangledTypeName, bindingTableSeparator);
382 }
383 
384 llvm::StringRef
385 fir::NameUniquer::dropTypeConversionMarkers(llvm::StringRef mangledTypeName) {
386   if (mangledTypeName.ends_with(boxprocSuffix))
387     return mangledTypeName.drop_back(boxprocSuffix.size());
388   return mangledTypeName;
389 }
390