xref: /llvm-project/flang/lib/Optimizer/Support/InternalNames.cpp (revision 95b4128c6a87e9b894aa75524e63be147cca790b)
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(tag).append(mod.lower());
39     tag = "S";
40   }
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;
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(init, 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(init, i - init).getAsInteger(10, 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